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:
parent
ce08681d81
commit
517e95adc2
21 changed files with 101 additions and 101 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
# ReceiptNext Configuration
|
# NextExpense Configuration
|
||||||
# Copy this file to .env and fill in your credentials.
|
# Copy this file to .env and fill in your credentials.
|
||||||
# Run `bash install.sh` for interactive setup.
|
# Run `bash install.sh` for interactive setup.
|
||||||
|
|
||||||
|
|
|
||||||
6
Makefile
6
Makefile
|
|
@ -1,4 +1,4 @@
|
||||||
# ReceiptNext — AI-Powered Expense Tracker
|
# NextExpense — AI-Powered Expense Tracker
|
||||||
# Makefile for build, install, and deployment
|
# Makefile for build, install, and deployment
|
||||||
|
|
||||||
BINARY = app
|
BINARY = app
|
||||||
|
|
@ -30,7 +30,7 @@ build-all: build-linux-amd64 build-linux-arm64
|
||||||
# -------------------------------------------------------------------
|
# -------------------------------------------------------------------
|
||||||
|
|
||||||
install: build
|
install: build
|
||||||
@echo "==> Installing ReceiptNext..."
|
@echo "==> Installing NextExpense..."
|
||||||
cp $(BINARY) /usr/local/bin/$(BINARY)
|
cp $(BINARY) /usr/local/bin/$(BINARY)
|
||||||
@if [ ! -f /etc/$(BINARY)/.env ]; then \
|
@if [ ! -f /etc/$(BINARY)/.env ]; then \
|
||||||
mkdir -p /etc/$(BINARY); \
|
mkdir -p /etc/$(BINARY); \
|
||||||
|
|
@ -52,7 +52,7 @@ uninstall:
|
||||||
-rm -f /etc/systemd/system/$(BINARY).service
|
-rm -f /etc/systemd/system/$(BINARY).service
|
||||||
-systemctl daemon-reload
|
-systemctl daemon-reload
|
||||||
-rm -f /usr/local/bin/$(BINARY)
|
-rm -f /usr/local/bin/$(BINARY)
|
||||||
@echo "==> ReceiptNext uninstalled"
|
@echo "==> NextExpense uninstalled"
|
||||||
|
|
||||||
# -------------------------------------------------------------------
|
# -------------------------------------------------------------------
|
||||||
# Service management
|
# Service management
|
||||||
|
|
|
||||||
22
README.md
22
README.md
|
|
@ -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.
|
> 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
|
## 🚀 One-Command Install
|
||||||
|
|
||||||
```bash
|
```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:
|
Or from a local clone:
|
||||||
|
|
@ -20,7 +20,7 @@ Or from a local clone:
|
||||||
|
|
||||||
The installer will:
|
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)
|
2. Build the binary (pure Go, no CGO, no dependencies)
|
||||||
3. Ask which AI provider to use:
|
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)
|
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
|
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`.
|
**Result:** A fully configured, always-running expense tracker at `http://YOUR_SERVER:8080`.
|
||||||
|
|
||||||
|
|
@ -41,7 +41,7 @@ The installer will:
|
||||||
## 🔄 Updating
|
## 🔄 Updating
|
||||||
|
|
||||||
```bash
|
```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.
|
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
|
### Manual Build
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://git.lohmar.co.uk/cclohmar/ReceiptNext.git
|
git clone https://git.lohmar.co.uk/cclohmar/NextExpense.git
|
||||||
cd ReceiptNext
|
cd NextExpense
|
||||||
|
|
||||||
# Build for your current platform
|
# Build for your current platform
|
||||||
CGO_ENABLED=0 go build -buildvcs=false -ldflags="-s -w" -o app .
|
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
|
```bash
|
||||||
# If installed via systemd:
|
# If installed via systemd:
|
||||||
systemctl start receiptnext
|
systemctl start nextexpense
|
||||||
|
|
||||||
# Or run directly:
|
# Or run directly:
|
||||||
./app
|
./app
|
||||||
|
|
@ -160,7 +160,7 @@ Navigate to `http://YOUR_SERVER:8080`
|
||||||
## 🏗️ Project Structure
|
## 🏗️ Project Structure
|
||||||
|
|
||||||
```
|
```
|
||||||
/opt/receiptnext/
|
/opt/nextexpense/
|
||||||
├── app # Compiled binary
|
├── app # Compiled binary
|
||||||
├── .env # Configuration (optional)
|
├── .env # Configuration (optional)
|
||||||
├── backups/ # Automatic DB backups (from -update)
|
├── backups/ # Automatic DB backups (from -update)
|
||||||
|
|
@ -177,7 +177,7 @@ Navigate to `http://YOUR_SERVER:8080`
|
||||||
├── install.sh # Installer script
|
├── install.sh # Installer script
|
||||||
├── Makefile # Build targets
|
├── Makefile # Build targets
|
||||||
└── contrib/
|
└── contrib/
|
||||||
└── receiptnext.service # Systemd service file
|
└── nextexpense.service # Systemd service file
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
|
||||||
25
contrib/nextexpense.service
Normal file
25
contrib/nextexpense.service
Normal 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
|
||||||
|
|
@ -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
2
go.mod
|
|
@ -1,4 +1,4 @@
|
||||||
module github.com/cclohmar/ReceiptNext
|
module github.com/cclohmar/NextExpense
|
||||||
|
|
||||||
go 1.23.0
|
go 1.23.0
|
||||||
|
|
||||||
|
|
|
||||||
40
install.sh
40
install.sh
|
|
@ -1,22 +1,22 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
#
|
#
|
||||||
# ReceiptNext Installer
|
# NextExpense Installer
|
||||||
# =====================
|
# =====================
|
||||||
#
|
#
|
||||||
# Usage:
|
# 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 — Full install
|
||||||
# bash install.sh -update — Pull latest, rebuild, restart
|
# 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.
|
# Uses sudo internally only for operations that require it.
|
||||||
#
|
#
|
||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
INSTALL_DIR="/opt/receiptnext"
|
INSTALL_DIR="/opt/nextexpense"
|
||||||
SERVICE_NAME="receiptnext"
|
SERVICE_NAME="nextexpense"
|
||||||
REPO_URL="https://git.lohmar.co.uk/cclohmar/ReceiptNext.git"
|
REPO_URL="https://git.lohmar.co.uk/cclohmar/NextExpense.git"
|
||||||
|
|
||||||
RED='\033[0;31m'
|
RED='\033[0;31m'
|
||||||
GREEN='\033[0;32m'
|
GREEN='\033[0;32m'
|
||||||
|
|
@ -44,7 +44,7 @@ sudo_if() {
|
||||||
if [ "${1:-}" = "-update" ]; then
|
if [ "${1:-}" = "-update" ]; then
|
||||||
echo ""
|
echo ""
|
||||||
echo " ╔═══════════════════════════════════════╗"
|
echo " ╔═══════════════════════════════════════╗"
|
||||||
echo " ║ ReceiptNext — Update Mode ║"
|
echo " ║ NextExpense — Update Mode ║"
|
||||||
echo " ╚═══════════════════════════════════════╝"
|
echo " ╚═══════════════════════════════════════╝"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
|
|
@ -66,10 +66,10 @@ if [ "${1:-}" = "-update" ]; then
|
||||||
else
|
else
|
||||||
warn "Not a git repository — re-cloning..."
|
warn "Not a git repository — re-cloning..."
|
||||||
cd /tmp
|
cd /tmp
|
||||||
rm -rf receiptnext-update
|
rm -rf nextexpense-update
|
||||||
sudo_if git clone "$REPO_URL" receiptnext-update
|
sudo_if git clone "$REPO_URL" nextexpense-update
|
||||||
sudo_if rsync -a --delete receiptnext-update/ "$INSTALL_DIR/"
|
sudo_if rsync -a --delete nextexpense-update/ "$INSTALL_DIR/"
|
||||||
rm -rf receiptnext-update
|
rm -rf nextexpense-update
|
||||||
cd "$INSTALL_DIR"
|
cd "$INSTALL_DIR"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
@ -144,7 +144,7 @@ if [ "${1:-}" = "-update" ]; then
|
||||||
sleep 2
|
sleep 2
|
||||||
|
|
||||||
if systemctl is-active --quiet "$SERVICE_NAME"; then
|
if systemctl is-active --quiet "$SERVICE_NAME"; then
|
||||||
info "Update complete — ReceiptNext is running"
|
info "Update complete — NextExpense is running"
|
||||||
else
|
else
|
||||||
warn "Service did not start. Check: systemctl status $SERVICE_NAME"
|
warn "Service did not start. Check: systemctl status $SERVICE_NAME"
|
||||||
fi
|
fi
|
||||||
|
|
@ -156,7 +156,7 @@ fi
|
||||||
# ──────────────────────────────────────────────────────────────────
|
# ──────────────────────────────────────────────────────────────────
|
||||||
echo ""
|
echo ""
|
||||||
echo " ╔═══════════════════════════════════════╗"
|
echo " ╔═══════════════════════════════════════╗"
|
||||||
echo " ║ ReceiptNext Installer ║"
|
echo " ║ NextExpense Installer ║"
|
||||||
echo " ╚═══════════════════════════════════════╝"
|
echo " ╚═══════════════════════════════════════╝"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
|
|
@ -327,7 +327,7 @@ fi
|
||||||
# ── 7. Write .env ────────────────────────────────────────────────
|
# ── 7. Write .env ────────────────────────────────────────────────
|
||||||
info "Creating .env..."
|
info "Creating .env..."
|
||||||
sudo_if tee "$INSTALL_DIR/.env" > /dev/null << ENVEOF
|
sudo_if tee "$INSTALL_DIR/.env" > /dev/null << ENVEOF
|
||||||
# ReceiptNext Configuration
|
# NextExpense Configuration
|
||||||
# Generated by install.sh on $(date)
|
# Generated by install.sh on $(date)
|
||||||
|
|
||||||
PORT=${PORT}
|
PORT=${PORT}
|
||||||
|
|
@ -386,8 +386,8 @@ sudo_if chmod 775 "${INSTALL_DIR}/storage"
|
||||||
info "Creating systemd service..."
|
info "Creating systemd service..."
|
||||||
sudo_if tee "/etc/systemd/system/${SERVICE_NAME}.service" > /dev/null << SERVEOF
|
sudo_if tee "/etc/systemd/system/${SERVICE_NAME}.service" > /dev/null << SERVEOF
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=ReceiptNext — AI-Powered Expense Tracker
|
Description=NextExpense — AI-Powered Expense Tracker
|
||||||
Documentation=https://git.lohmar.co.uk/cclohmar/ReceiptNext
|
Documentation=https://git.lohmar.co.uk/cclohmar/NextExpense
|
||||||
After=network.target
|
After=network.target
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
|
|
@ -399,8 +399,8 @@ ExecStart=${INSTALL_DIR}/app
|
||||||
Restart=always
|
Restart=always
|
||||||
RestartSec=5
|
RestartSec=5
|
||||||
EnvironmentFile=-${INSTALL_DIR}/.env
|
EnvironmentFile=-${INSTALL_DIR}/.env
|
||||||
StandardOutput=append:/var/log/receiptnext.log
|
StandardOutput=append:/var/log/nextexpense.log
|
||||||
StandardError=append:/var/log/receiptnext.log
|
StandardError=append:/var/log/nextexpense.log
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
||||||
|
|
@ -411,7 +411,7 @@ sudo_if systemctl enable "${SERVICE_NAME}"
|
||||||
info "Service created: /etc/systemd/system/${SERVICE_NAME}.service"
|
info "Service created: /etc/systemd/system/${SERVICE_NAME}.service"
|
||||||
|
|
||||||
# ── 9. Start ─────────────────────────────────────────────────────
|
# ── 9. Start ─────────────────────────────────────────────────────
|
||||||
info "Starting ReceiptNext..."
|
info "Starting NextExpense..."
|
||||||
sudo_if systemctl restart "${SERVICE_NAME}" 2>/dev/null || true
|
sudo_if systemctl restart "${SERVICE_NAME}" 2>/dev/null || true
|
||||||
sleep 2
|
sleep 2
|
||||||
|
|
||||||
|
|
@ -431,7 +431,7 @@ echo " Logs: journalctl -u $SERVICE_NAME -f"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
if systemctl is-active --quiet "${SERVICE_NAME}"; then
|
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)"
|
echo " Open http://localhost:${PORT} (or your server IP)"
|
||||||
else
|
else
|
||||||
warn "Service did not start. Check: systemctl status ${SERVICE_NAME}"
|
warn "Service did not start. Check: systemctl status ${SERVICE_NAME}"
|
||||||
|
|
|
||||||
|
|
@ -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.
|
// verification codes and expense report emails with CSV or PDF attachments.
|
||||||
//
|
//
|
||||||
// Credentials are passed via the constructor; the caller is responsible for
|
// 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.
|
// 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.
|
// The email contains a standard subject line and the 6-digit verification code.
|
||||||
func (s *Sender) SendOTP(to, code string) error {
|
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)
|
body := fmt.Sprintf("Your verification code is: %s", code)
|
||||||
|
|
||||||
msg := buildPlainMessage(s.from, to, subject, body)
|
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, "From", from)
|
||||||
writeHeader(&b, "To", to)
|
writeHeader(&b, "To", to)
|
||||||
writeHeader(&b, "Subject", subject)
|
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))
|
writeHeader(&b, "Date", time.Now().Format(time.RFC1123Z))
|
||||||
|
|
||||||
// Create a multipart writer using a unique boundary string.
|
// Create a multipart writer using a unique boundary string.
|
||||||
|
|
|
||||||
|
|
@ -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,
|
// passwordless email OTP authentication, event management, expense tracking,
|
||||||
// and report generation endpoints.
|
// and report generation endpoints.
|
||||||
package handlers
|
package handlers
|
||||||
|
|
@ -14,10 +14,10 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/cclohmar/ReceiptNext/internal/auth"
|
"github.com/cclohmar/NextExpense/internal/auth"
|
||||||
"github.com/cclohmar/ReceiptNext/internal/database"
|
"github.com/cclohmar/NextExpense/internal/database"
|
||||||
"github.com/cclohmar/ReceiptNext/internal/email"
|
"github.com/cclohmar/NextExpense/internal/email"
|
||||||
"github.com/cclohmar/ReceiptNext/internal/utils"
|
"github.com/cclohmar/NextExpense/internal/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -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
|
// This file implements event management endpoints including dashboard
|
||||||
// listing, event creation, reopening, and expense viewing.
|
// listing, event creation, reopening, and expense viewing.
|
||||||
|
|
@ -15,8 +15,8 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/cclohmar/ReceiptNext/internal/database"
|
"github.com/cclohmar/NextExpense/internal/database"
|
||||||
"github.com/cclohmar/ReceiptNext/internal/utils"
|
"github.com/cclohmar/NextExpense/internal/utils"
|
||||||
"github.com/go-chi/chi/v5"
|
"github.com/go-chi/chi/v5"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
// This file implements expense upload, AI extraction, and save handlers
|
||||||
// that drive the core receipt capture workflow using HTMX partial responses.
|
// that drive the core receipt capture workflow using HTMX partial responses.
|
||||||
|
|
@ -24,9 +24,9 @@ import (
|
||||||
"github.com/go-chi/chi/v5"
|
"github.com/go-chi/chi/v5"
|
||||||
"golang.org/x/image/draw"
|
"golang.org/x/image/draw"
|
||||||
|
|
||||||
"github.com/cclohmar/ReceiptNext/internal/ai"
|
"github.com/cclohmar/NextExpense/internal/ai"
|
||||||
"github.com/cclohmar/ReceiptNext/internal/database"
|
"github.com/cclohmar/NextExpense/internal/database"
|
||||||
"github.com/cclohmar/ReceiptNext/internal/utils"
|
"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}$`)
|
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}$`)
|
||||||
|
|
|
||||||
|
|
@ -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
|
// This file implements the event filing workflow — generating CSV or PDF
|
||||||
// expense reports and emailing them as attachments to a specified recipient.
|
// expense reports and emailing them as attachments to a specified recipient.
|
||||||
|
|
@ -23,8 +23,8 @@ import (
|
||||||
"github.com/go-chi/chi/v5"
|
"github.com/go-chi/chi/v5"
|
||||||
"github.com/jung-kurt/gofpdf"
|
"github.com/jung-kurt/gofpdf"
|
||||||
|
|
||||||
"github.com/cclohmar/ReceiptNext/internal/database"
|
"github.com/cclohmar/NextExpense/internal/database"
|
||||||
"github.com/cclohmar/ReceiptNext/internal/email"
|
"github.com/cclohmar/NextExpense/internal/email"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Package utils provides common utility functions for ReceiptNext.
|
// Package utils provides common utility functions for NextExpense.
|
||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
|
||||||
14
main.go
14
main.go
|
|
@ -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
|
// A production-ready, mobile-first Progressive Web App (PWA) that uses
|
||||||
// passwordless email OTP login, event-based expense tracking, AI receipt
|
// passwordless email OTP login, event-based expense tracking, AI receipt
|
||||||
|
|
@ -27,11 +27,11 @@ import (
|
||||||
"github.com/go-chi/chi/v5/middleware"
|
"github.com/go-chi/chi/v5/middleware"
|
||||||
"github.com/joho/godotenv"
|
"github.com/joho/godotenv"
|
||||||
|
|
||||||
"github.com/cclohmar/ReceiptNext/internal/auth"
|
"github.com/cclohmar/NextExpense/internal/auth"
|
||||||
"github.com/cclohmar/ReceiptNext/internal/database"
|
"github.com/cclohmar/NextExpense/internal/database"
|
||||||
"github.com/cclohmar/ReceiptNext/internal/email"
|
"github.com/cclohmar/NextExpense/internal/email"
|
||||||
"github.com/cclohmar/ReceiptNext/internal/handlers"
|
"github.com/cclohmar/NextExpense/internal/handlers"
|
||||||
"github.com/cclohmar/ReceiptNext/internal/utils"
|
"github.com/cclohmar/NextExpense/internal/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
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)
|
log.Printf("INFO main: open http://localhost%s in your browser", addr)
|
||||||
|
|
||||||
if err := srv.ListenAndServe(); err != http.ErrServerClosed {
|
if err := srv.ListenAndServe(); err != http.ErrServerClosed {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/* ==========================================================================
|
/* ==========================================================================
|
||||||
ReceiptNext — PWA Expense Tracker Stylesheet
|
NextExpense — PWA Expense Tracker Stylesheet
|
||||||
"The Terminal Mint" dark palette | Mobile-first responsive
|
"The Terminal Mint" dark palette | Mobile-first responsive
|
||||||
========================================================================== */
|
========================================================================== */
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "ReceiptNext",
|
"name": "NextExpense",
|
||||||
"short_name": "ReceiptNext",
|
"short_name": "NextExpense",
|
||||||
"start_url": "/",
|
"start_url": "/",
|
||||||
"display": "standalone",
|
"display": "standalone",
|
||||||
"theme_color": "#10b981",
|
"theme_color": "#10b981",
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
/* ============================================================
|
/* ============================================================
|
||||||
* ReceiptNext — Service Worker
|
* NextExpense — Service Worker
|
||||||
* Version: 2.0.0
|
* Version: 2.0.0
|
||||||
* Cache name: receiptnext-v2
|
* Cache name: nextexpense-v2
|
||||||
* Strategy: Cache-first for shell assets, network-only for API
|
* 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
|
// Shell assets to pre-cache on install
|
||||||
const SHELL_ASSETS = [
|
const SHELL_ASSETS = [
|
||||||
|
|
@ -195,7 +195,7 @@ self.addEventListener('fetch', event => {
|
||||||
// Return a minimal offline fallback for navigations
|
// Return a minimal offline fallback for navigations
|
||||||
if (request.mode === 'navigate') {
|
if (request.mode === 'navigate') {
|
||||||
return new Response(
|
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,
|
status: 503,
|
||||||
statusText: 'Service Unavailable',
|
statusText: 'Service Unavailable',
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||||
<meta name="theme-color" content="#10b981">
|
<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="icon" type="image/svg+xml" href="/static/favicon.svg">
|
||||||
<link rel="alternate icon" href="/static/icons/icon-192.png">
|
<link rel="alternate icon" href="/static/icons/icon-192.png">
|
||||||
<link rel="manifest" href="/manifest.json">
|
<link rel="manifest" href="/manifest.json">
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
<body>
|
<body>
|
||||||
<div class="app-shell">
|
<div class="app-shell">
|
||||||
<header class="app-header">
|
<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;">
|
<div style="display: flex; gap: 0.5rem;">
|
||||||
<button class="btn btn-secondary btn-sm" style="font-size: 0.75rem;"
|
<button class="btn btn-secondary btn-sm" style="font-size: 0.75rem;"
|
||||||
hx-get="/profile" hx-target="body" hx-push-url="true">Profile</button>
|
hx-get="/profile" hx-target="body" hx-push-url="true">Profile</button>
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||||
<meta name="theme-color" content="#10b981">
|
<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="icon" type="image/svg+xml" href="/static/favicon.svg">
|
||||||
<link rel="alternate icon" href="/static/icons/icon-192.png">
|
<link rel="alternate icon" href="/static/icons/icon-192.png">
|
||||||
<link rel="manifest" href="/manifest.json">
|
<link rel="manifest" href="/manifest.json">
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
<meta name="theme-color" content="#10b981">
|
<meta name="theme-color" content="#10b981">
|
||||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||||
<meta name="apple-mobile-web-app-status-bar-style" content="default">
|
<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="icon" type="image/svg+xml" href="/static/favicon.svg">
|
||||||
<link rel="alternate icon" href="/static/icons/icon-192.png">
|
<link rel="alternate icon" href="/static/icons/icon-192.png">
|
||||||
<link rel="manifest" href="/manifest.json">
|
<link rel="manifest" href="/manifest.json">
|
||||||
|
|
@ -19,7 +19,7 @@
|
||||||
<div class="card login-card">
|
<div class="card login-card">
|
||||||
<div class="login-brand">
|
<div class="login-brand">
|
||||||
<div class="login-icon"><img src="/static/favicon.svg" width="48" height="48" alt="Rx"></div>
|
<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>
|
<p class="text-secondary">AI-Powered Expense Tracking</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||||
<meta name="theme-color" content="#10b981">
|
<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="icon" type="image/svg+xml" href="/static/favicon.svg">
|
||||||
<link rel="stylesheet" href="/static/css/style.css?v=4">
|
<link rel="stylesheet" href="/static/css/style.css?v=4">
|
||||||
<script src="https://unpkg.com/htmx.org@1.9.10"></script>
|
<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>
|
<h1 class="app-title" style="font-size: 1.1rem;">Edit Profile</h1>
|
||||||
<span></span>
|
<span></span>
|
||||||
{{else}}
|
{{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}}
|
{{end}}
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue