Configure
The admin creates cardholders and stores, then chooses the public hostname and secret upload code.
receipt-uploadSelf-hosted receipt collection
A small Go application for collecting phone-camera receipts through a private link, combining images into compact PDFs, and giving one administrator a clean review queue.
Single binary · SQLite · Local storageQuick start
Build the binary, initialize its config and data directory, replace the default password, then start the server.
make install
receipt-upload init
# Edit ADMIN_PASSWORD in ./config/.env
receipt-upload config check
receipt-upload servehttp://localhost:8725/. Administration lives at /admin/login.How it works
The admin creates cardholders and stores, then chooses the public hostname and secret upload code.
Send the generated private upload URL to cardholders. They do not create accounts or sign in.
Cardholders select their name, add expense details, and attach one or more receipt photos.
The app resizes images, builds one PDF per expense, and makes it available in the admin portal.
Configuration
The application reads the file passed with --config (default: ./config/.env). Runtime environment variables are not merged in.
ADMIN_USERNAMEAdministrator login nameADMIN_PASSWORDAdministrator passwordSECRET_KEYSigns admin session cookiesUPLOAD_TOKENInitial private upload-link tokenAPP_BASE_URLPublic origin used when building linksDATA_DIRSQLite database and receipt PDFsMAX_UPLOAD_MBMaximum size of one submissionDeployment
receipt-upload serve \
--config ./runtime/app.env \
--host 0.0.0.0 \
--port 8725docker build -t receipt-upload .
docker run --rm -p 8725:8725 \
-v "$PWD/config/.env:/app/config/.env:ro" \
-v receipt-upload-data:/app/data \
receipt-uploadPersist DATA_DIR. It contains both app.sqlite3 and generated receipt PDFs.
Operational notes
Phone photos are resized to a maximum 1600px dimension and JPEG-compressed before PDF generation. No external converter is required.
Metadata lives in one SQLite database and receipt PDFs live beside it under the configured data directory.
Three failed login attempts ban an IP for 24 hours. The CLI can list and remove ban records.