chore: rebrand ReceiptNext to NextExpense

- 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
This commit is contained in:
Claus Lohmar 2026-06-21 18:39:48 +00:00
parent ce08681d81
commit 517e95adc2
21 changed files with 101 additions and 101 deletions

View file

@ -1,4 +1,4 @@
# ReceiptNext Configuration
# NextExpense Configuration
# Copy this file to .env and fill in your credentials.
# Run `bash install.sh` for interactive setup.

View file

@ -1,4 +1,4 @@
# ReceiptNext — AI-Powered Expense Tracker
# NextExpense — AI-Powered Expense Tracker
# Makefile for build, install, and deployment
BINARY = app
@ -30,7 +30,7 @@ build-all: build-linux-amd64 build-linux-arm64
# -------------------------------------------------------------------
install: build
@echo "==> Installing ReceiptNext..."
@echo "==> Installing NextExpense..."
cp $(BINARY) /usr/local/bin/$(BINARY)
@if [ ! -f /etc/$(BINARY)/.env ]; then \
mkdir -p /etc/$(BINARY); \
@ -52,7 +52,7 @@ uninstall:
-rm -f /etc/systemd/system/$(BINARY).service
-systemctl daemon-reload
-rm -f /usr/local/bin/$(BINARY)
@echo "==> ReceiptNext uninstalled"
@echo "==> NextExpense uninstalled"
# -------------------------------------------------------------------
# Service management

View file

@ -1,4 +1,4 @@
# ReceiptNext — AI-Powered Expense Tracker
# 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.
@ -9,7 +9,7 @@
## 🚀 One-Command Install
```bash
bash -c "$(curl -fsSL https://git.lohmar.co.uk/cclohmar/ReceiptNext/raw/branch/main/install.sh)"
bash -c "$(curl -fsSL https://git.lohmar.co.uk/cclohmar/NextExpense/raw/branch/main/install.sh)"
```
Or from a local clone:
@ -20,7 +20,7 @@ Or from a local clone:
The installer will:
1. Clone the repo to `/opt/receiptnext/`
1. Clone the repo to `/opt/nextexpense/`
2. Build the binary (pure Go, no CGO, no dependencies)
3. Ask which AI provider to use:
@ -30,9 +30,9 @@ The installer will:
```
4. Prompt for SMTP settings (for OTP emails and report delivery)
5. Create `/opt/receiptnext/.env` with all configuration
5. Create `/opt/nextexpense/.env` with all configuration
6. Set up a systemd service that auto-starts on boot
7. Start ReceiptNext
7. Start NextExpense
**Result:** A fully configured, always-running expense tracker at `http://YOUR_SERVER:8080`.
@ -41,7 +41,7 @@ The installer will:
## 🔄 Updating
```bash
bash /opt/receiptnext/install.sh -update
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.
@ -56,8 +56,8 @@ No pre-built binaries are distributed — building from source guarantees the la
### Manual Build
```bash
git clone https://git.lohmar.co.uk/cclohmar/ReceiptNext.git
cd ReceiptNext
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 .
@ -102,7 +102,7 @@ Configuration is via environment variables in `.env`. The install script builds
```bash
# If installed via systemd:
systemctl start receiptnext
systemctl start nextexpense
# Or run directly:
./app
@ -160,7 +160,7 @@ Navigate to `http://YOUR_SERVER:8080`
## 🏗️ Project Structure
```
/opt/receiptnext/
/opt/nextexpense/
├── app # Compiled binary
├── .env # Configuration (optional)
├── backups/ # Automatic DB backups (from -update)
@ -177,7 +177,7 @@ Navigate to `http://YOUR_SERVER:8080`
├── install.sh # Installer script
├── Makefile # Build targets
└── contrib/
└── receiptnext.service # Systemd service file
└── nextexpense.service # Systemd service file
```
---

View file

@ -0,0 +1,25 @@
[Unit]
Description=NextExpense — AI-Powered Expense Tracker
Documentation=https://git.lohmar.co.uk/cclohmar/NextExpense
After=network.target
[Service]
Type=simple
User=nextexpense
Group=nextexpense
WorkingDirectory=/opt/nextexpense
ExecStart=/opt/nextexpense/app
Restart=always
RestartSec=5
EnvironmentFile=-/opt/nextexpense/.env
StandardOutput=append:/var/log/nextexpense.log
StandardError=append:/var/log/nextexpense.log
# Security hardening
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=full
ProtectHome=true
[Install]
WantedBy=multi-user.target

View file

@ -1,25 +0,0 @@
[Unit]
Description=ReceiptNext — AI-Powered Expense Tracker
Documentation=https://git.lohmar.co.uk/cclohmar/ReceiptNext
After=network.target
[Service]
Type=simple
User=receiptnext
Group=receiptnext
WorkingDirectory=/opt/receiptnext
ExecStart=/opt/receiptnext/app
Restart=always
RestartSec=5
EnvironmentFile=-/opt/receiptnext/.env
StandardOutput=append:/var/log/receiptnext.log
StandardError=append:/var/log/receiptnext.log
# Security hardening
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=full
ProtectHome=true
[Install]
WantedBy=multi-user.target

2
go.mod
View file

@ -1,4 +1,4 @@
module github.com/cclohmar/ReceiptNext
module github.com/cclohmar/NextExpense
go 1.23.0

View file

@ -1,22 +1,22 @@
#!/usr/bin/env bash
#
# ReceiptNext Installer
# NextExpense Installer
# =====================
#
# Usage:
# curl -fsSL https://git.lohmar.co.uk/cclohmar/ReceiptNext/raw/branch/main/install.sh | bash
# curl -fsSL https://git.lohmar.co.uk/cclohmar/NextExpense/raw/branch/main/install.sh | bash
# bash install.sh — Full install
# bash install.sh -update — Pull latest, rebuild, restart
#
# Installs to /opt/receiptnext/ and sets up a systemd service.
# Installs to /opt/nextexpense/ and sets up a systemd service.
# Uses sudo internally only for operations that require it.
#
set -euo pipefail
INSTALL_DIR="/opt/receiptnext"
SERVICE_NAME="receiptnext"
REPO_URL="https://git.lohmar.co.uk/cclohmar/ReceiptNext.git"
INSTALL_DIR="/opt/nextexpense"
SERVICE_NAME="nextexpense"
REPO_URL="https://git.lohmar.co.uk/cclohmar/NextExpense.git"
RED='\033[0;31m'
GREEN='\033[0;32m'
@ -44,7 +44,7 @@ sudo_if() {
if [ "${1:-}" = "-update" ]; then
echo ""
echo " ╔═══════════════════════════════════════╗"
echo " ║ ReceiptNext — Update Mode ║"
echo " ║ NextExpense — Update Mode ║"
echo " ╚═══════════════════════════════════════╝"
echo ""
@ -66,10 +66,10 @@ if [ "${1:-}" = "-update" ]; then
else
warn "Not a git repository — re-cloning..."
cd /tmp
rm -rf receiptnext-update
sudo_if git clone "$REPO_URL" receiptnext-update
sudo_if rsync -a --delete receiptnext-update/ "$INSTALL_DIR/"
rm -rf receiptnext-update
rm -rf nextexpense-update
sudo_if git clone "$REPO_URL" nextexpense-update
sudo_if rsync -a --delete nextexpense-update/ "$INSTALL_DIR/"
rm -rf nextexpense-update
cd "$INSTALL_DIR"
fi
@ -144,7 +144,7 @@ if [ "${1:-}" = "-update" ]; then
sleep 2
if systemctl is-active --quiet "$SERVICE_NAME"; then
info "Update complete — ReceiptNext is running"
info "Update complete — NextExpense is running"
else
warn "Service did not start. Check: systemctl status $SERVICE_NAME"
fi
@ -156,7 +156,7 @@ fi
# ──────────────────────────────────────────────────────────────────
echo ""
echo " ╔═══════════════════════════════════════╗"
echo " ║ ReceiptNext Installer ║"
echo " ║ NextExpense Installer ║"
echo " ╚═══════════════════════════════════════╝"
echo ""
@ -327,7 +327,7 @@ fi
# ── 7. Write .env ────────────────────────────────────────────────
info "Creating .env..."
sudo_if tee "$INSTALL_DIR/.env" > /dev/null << ENVEOF
# ReceiptNext Configuration
# NextExpense Configuration
# Generated by install.sh on $(date)
PORT=${PORT}
@ -386,8 +386,8 @@ sudo_if chmod 775 "${INSTALL_DIR}/storage"
info "Creating systemd service..."
sudo_if tee "/etc/systemd/system/${SERVICE_NAME}.service" > /dev/null << SERVEOF
[Unit]
Description=ReceiptNext — AI-Powered Expense Tracker
Documentation=https://git.lohmar.co.uk/cclohmar/ReceiptNext
Description=NextExpense — AI-Powered Expense Tracker
Documentation=https://git.lohmar.co.uk/cclohmar/NextExpense
After=network.target
[Service]
@ -399,8 +399,8 @@ ExecStart=${INSTALL_DIR}/app
Restart=always
RestartSec=5
EnvironmentFile=-${INSTALL_DIR}/.env
StandardOutput=append:/var/log/receiptnext.log
StandardError=append:/var/log/receiptnext.log
StandardOutput=append:/var/log/nextexpense.log
StandardError=append:/var/log/nextexpense.log
[Install]
WantedBy=multi-user.target
@ -411,7 +411,7 @@ sudo_if systemctl enable "${SERVICE_NAME}"
info "Service created: /etc/systemd/system/${SERVICE_NAME}.service"
# ── 9. Start ─────────────────────────────────────────────────────
info "Starting ReceiptNext..."
info "Starting NextExpense..."
sudo_if systemctl restart "${SERVICE_NAME}" 2>/dev/null || true
sleep 2
@ -431,7 +431,7 @@ echo " Logs: journalctl -u $SERVICE_NAME -f"
echo ""
if systemctl is-active --quiet "${SERVICE_NAME}"; then
info "ReceiptNext is running on port ${PORT}"
info "NextExpense is running on port ${PORT}"
echo " Open http://localhost:${PORT} (or your server IP)"
else
warn "Service did not start. Check: systemctl status ${SERVICE_NAME}"

View file

@ -1,4 +1,4 @@
// Package email provides SMTP email sending for ExpenseFlow, including OTP
// Package email provides SMTP email sending for NextExpense, including OTP
// verification codes and expense report emails with CSV or PDF attachments.
//
// Credentials are passed via the constructor; the caller is responsible for
@ -62,7 +62,7 @@ func NewSender(host, port, user, pass, from string) *Sender {
// SendOTP sends a plain-text OTP verification email to the given recipient.
// The email contains a standard subject line and the 6-digit verification code.
func (s *Sender) SendOTP(to, code string) error {
subject := "Your ReceiptNext OTP"
subject := "Your NextExpense OTP"
body := fmt.Sprintf("Your verification code is: %s", code)
msg := buildPlainMessage(s.from, to, subject, body)
@ -194,7 +194,7 @@ func buildMultipartMessage(from, to, subject, body string, attachments []*Attach
writeHeader(&b, "From", from)
writeHeader(&b, "To", to)
writeHeader(&b, "Subject", subject)
writeHeader(&b, "Message-ID", fmt.Sprintf("<%d.receiptnext@post.2-4-h.app>", time.Now().UnixNano()))
writeHeader(&b, "Message-ID", fmt.Sprintf("<%d.nextexpense@post.2-4-h.app>", time.Now().UnixNano()))
writeHeader(&b, "Date", time.Now().Format(time.RFC1123Z))
// Create a multipart writer using a unique boundary string.

View file

@ -1,4 +1,4 @@
// Package handlers implements HTTP handlers for ExpenseFlow, providing
// Package handlers implements HTTP handlers for NextExpense, providing
// passwordless email OTP authentication, event management, expense tracking,
// and report generation endpoints.
package handlers
@ -14,10 +14,10 @@ import (
"sync"
"time"
"github.com/cclohmar/ReceiptNext/internal/auth"
"github.com/cclohmar/ReceiptNext/internal/database"
"github.com/cclohmar/ReceiptNext/internal/email"
"github.com/cclohmar/ReceiptNext/internal/utils"
"github.com/cclohmar/NextExpense/internal/auth"
"github.com/cclohmar/NextExpense/internal/database"
"github.com/cclohmar/NextExpense/internal/email"
"github.com/cclohmar/NextExpense/internal/utils"
)
// ---------------------------------------------------------------------------

View file

@ -1,4 +1,4 @@
// Package handlers provides HTTP request handlers for ExpenseFlow.
// Package handlers provides HTTP request handlers for NextExpense.
//
// This file implements event management endpoints including dashboard
// listing, event creation, reopening, and expense viewing.
@ -15,8 +15,8 @@ import (
"strconv"
"time"
"github.com/cclohmar/ReceiptNext/internal/database"
"github.com/cclohmar/ReceiptNext/internal/utils"
"github.com/cclohmar/NextExpense/internal/database"
"github.com/cclohmar/NextExpense/internal/utils"
"github.com/go-chi/chi/v5"
)

View file

@ -1,4 +1,4 @@
// Package handlers provides HTTP request handlers for ExpenseFlow.
// Package handlers provides HTTP request handlers for NextExpense.
//
// This file implements expense upload, AI extraction, and save handlers
// that drive the core receipt capture workflow using HTMX partial responses.
@ -24,9 +24,9 @@ import (
"github.com/go-chi/chi/v5"
"golang.org/x/image/draw"
"github.com/cclohmar/ReceiptNext/internal/ai"
"github.com/cclohmar/ReceiptNext/internal/database"
"github.com/cclohmar/ReceiptNext/internal/utils"
"github.com/cclohmar/NextExpense/internal/ai"
"github.com/cclohmar/NextExpense/internal/database"
"github.com/cclohmar/NextExpense/internal/utils"
)
var uuidRe = regexp.MustCompile(`^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$`)

View file

@ -1,4 +1,4 @@
// Package handlers implements HTTP request handlers for ExpenseFlow.
// Package handlers implements HTTP request handlers for NextExpense.
//
// This file implements the event filing workflow — generating CSV or PDF
// expense reports and emailing them as attachments to a specified recipient.
@ -23,8 +23,8 @@ import (
"github.com/go-chi/chi/v5"
"github.com/jung-kurt/gofpdf"
"github.com/cclohmar/ReceiptNext/internal/database"
"github.com/cclohmar/ReceiptNext/internal/email"
"github.com/cclohmar/NextExpense/internal/database"
"github.com/cclohmar/NextExpense/internal/email"
)
// ---------------------------------------------------------------------------

View file

@ -1,4 +1,4 @@
// Package utils provides common utility functions for ReceiptNext.
// Package utils provides common utility functions for NextExpense.
package utils
import (

14
main.go
View file

@ -1,4 +1,4 @@
// ReceiptNext — AI-Powered Expense Tracker
// NextExpense — AI-Powered Expense Tracker
//
// A production-ready, mobile-first Progressive Web App (PWA) that uses
// passwordless email OTP login, event-based expense tracking, AI receipt
@ -27,11 +27,11 @@ import (
"github.com/go-chi/chi/v5/middleware"
"github.com/joho/godotenv"
"github.com/cclohmar/ReceiptNext/internal/auth"
"github.com/cclohmar/ReceiptNext/internal/database"
"github.com/cclohmar/ReceiptNext/internal/email"
"github.com/cclohmar/ReceiptNext/internal/handlers"
"github.com/cclohmar/ReceiptNext/internal/utils"
"github.com/cclohmar/NextExpense/internal/auth"
"github.com/cclohmar/NextExpense/internal/database"
"github.com/cclohmar/NextExpense/internal/email"
"github.com/cclohmar/NextExpense/internal/handlers"
"github.com/cclohmar/NextExpense/internal/utils"
)
func main() {
@ -274,7 +274,7 @@ func main() {
}
}()
log.Printf("INFO main: ReceiptNext server starting on %s", addr)
log.Printf("INFO main: NextExpense server starting on %s", addr)
log.Printf("INFO main: open http://localhost%s in your browser", addr)
if err := srv.ListenAndServe(); err != http.ErrServerClosed {

View file

@ -1,5 +1,5 @@
/* ==========================================================================
ReceiptNext PWA Expense Tracker Stylesheet
NextExpense PWA Expense Tracker Stylesheet
"The Terminal Mint" dark palette | Mobile-first responsive
========================================================================== */

View file

@ -1,6 +1,6 @@
{
"name": "ReceiptNext",
"short_name": "ReceiptNext",
"name": "NextExpense",
"short_name": "NextExpense",
"start_url": "/",
"display": "standalone",
"theme_color": "#10b981",

View file

@ -1,11 +1,11 @@
/* ============================================================
* ReceiptNext Service Worker
* NextExpense Service Worker
* Version: 2.0.0
* Cache name: receiptnext-v2
* Cache name: nextexpense-v2
* Strategy: Cache-first for shell assets, network-only for API
* ============================================================ */
const CACHE_NAME = 'receiptnext-v1';
const CACHE_NAME = 'nextexpense-v1';
// Shell assets to pre-cache on install
const SHELL_ASSETS = [
@ -195,7 +195,7 @@ self.addEventListener('fetch', event => {
// Return a minimal offline fallback for navigations
if (request.mode === 'navigate') {
return new Response(
'<!DOCTYPE html><html><head><title>Offline — ReceiptNext</title><meta name="viewport" content="width=device-width, initial-scale=1"><style>body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;display:flex;flex-direction:column;align-items:center;justify-content:center;min-height:100vh;margin:0;padding:2rem;text-align:center;background:#0f172a;color:#f8fafc}h1{font-size:1.5rem;margin-bottom:0.5rem}p{color:#94a3b8;max-width:24rem}</style></head><body><h1>You\'re offline</h1><p>ReceiptNext needs an internet connection to load. Please check your connection and try again.</p></body></html>',
'<!DOCTYPE html><html><head><title>Offline — NextExpense</title><meta name="viewport" content="width=device-width, initial-scale=1"><style>body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;display:flex;flex-direction:column;align-items:center;justify-content:center;min-height:100vh;margin:0;padding:2rem;text-align:center;background:#0f172a;color:#f8fafc}h1{font-size:1.5rem;margin-bottom:0.5rem}p{color:#94a3b8;max-width:24rem}</style></head><body><h1>You\'re offline</h1><p>NextExpense needs an internet connection to load. Please check your connection and try again.</p></body></html>',
{
status: 503,
statusText: 'Service Unavailable',

View file

@ -4,7 +4,7 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<meta name="theme-color" content="#10b981">
<title>ReceiptNext</title>
<title>NextExpense</title>
<link rel="icon" type="image/svg+xml" href="/static/favicon.svg">
<link rel="alternate icon" href="/static/icons/icon-192.png">
<link rel="manifest" href="/manifest.json">
@ -14,7 +14,7 @@
<body>
<div class="app-shell">
<header class="app-header">
<h1 class="app-title"><img src="/static/favicon.svg" width="24" height="24" alt="" style="vertical-align: middle; margin-right: 0.5rem;">ReceiptNext</h1>
<h1 class="app-title"><img src="/static/favicon.svg" width="24" height="24" alt="" style="vertical-align: middle; margin-right: 0.5rem;">NextExpense</h1>
<div style="display: flex; gap: 0.5rem;">
<button class="btn btn-secondary btn-sm" style="font-size: 0.75rem;"
hx-get="/profile" hx-target="body" hx-push-url="true">Profile</button>

View file

@ -4,7 +4,7 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<meta name="theme-color" content="#10b981">
<title>{{.Event.Name}} - ReceiptNext</title>
<title>{{.Event.Name}} - NextExpense</title>
<link rel="icon" type="image/svg+xml" href="/static/favicon.svg">
<link rel="alternate icon" href="/static/icons/icon-192.png">
<link rel="manifest" href="/manifest.json">

View file

@ -6,7 +6,7 @@
<meta name="theme-color" content="#10b981">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<title>ReceiptNext</title>
<title>NextExpense</title>
<link rel="icon" type="image/svg+xml" href="/static/favicon.svg">
<link rel="alternate icon" href="/static/icons/icon-192.png">
<link rel="manifest" href="/manifest.json">
@ -19,7 +19,7 @@
<div class="card login-card">
<div class="login-brand">
<div class="login-icon"><img src="/static/favicon.svg" width="48" height="48" alt="Rx"></div>
<h1>ReceiptNext</h1>
<h1>NextExpense</h1>
<p class="text-secondary">AI-Powered Expense Tracking</p>
</div>

View file

@ -4,7 +4,7 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<meta name="theme-color" content="#10b981">
<title>{{if .Editing}}Profile{{else}}Welcome{{end}} - ReceiptNext</title>
<title>{{if .Editing}}Profile{{else}}Welcome{{end}} - NextExpense</title>
<link rel="icon" type="image/svg+xml" href="/static/favicon.svg">
<link rel="stylesheet" href="/static/css/style.css?v=4">
<script src="https://unpkg.com/htmx.org@1.9.10"></script>
@ -18,7 +18,7 @@
<h1 class="app-title" style="font-size: 1.1rem;">Edit Profile</h1>
<span></span>
{{else}}
<h1 class="app-title" style="font-size: 1.1rem;">Welcome to ReceiptNext</h1>
<h1 class="app-title" style="font-size: 1.1rem;">Welcome to NextExpense</h1>
{{end}}
</header>