app to track my HSA eligible receipts
Find a file
Jean-Michel Tremblay 344663d87d Add local receipt OCR + grouping (OCR/)
Two local, GPU-backed tools that talk to a local ollama server (no cloud,
no API key):

- receipt_ocr.py: receipt image -> ordered list of rows of text, via
  Qwen2.5-VL 7B. Zero deps (stdlib + ollama HTTP API).
- receipt_group.py: OCR rows -> structured receipt (store, line items with
  multi-row details merged, total, metadata), via Mistral Small 24B. Detail
  rows are attached by arithmetic reconciliation, not position; a prompt
  completeness clause guards against dropped rows; a deterministic --json
  reconciliation pass audits item math, subtotal/total, and unit count.

README documents setup, an ollama operating runbook, and design rationale.
Includes the ALDI example image + its OCR rows.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 22:48:17 -04:00
.forgejo/workflows CI: auto-deploy on release tags, drop manual deploy workflow 2026-06-19 15:45:50 -04:00
cmd/hsa Add scheduled metadata-only DB backups (spec item 11) 2026-06-19 07:12:50 -04:00
deploy Add deploy docs (CICD + Authelia/OIDC); changelog 0.1.0 2026-06-20 21:20:08 -04:00
internal Security hardening: server-side session expiry + nosniff on files 2026-06-20 20:56:38 -04:00
OCR Add local receipt OCR + grouping (OCR/) 2026-06-22 22:48:17 -04:00
scripts Static portable build + env-file launcher for deployment 2026-06-19 08:32:19 -04:00
.env.example Backups: ROOT/dbbackup, hsa_sqlite_backup_YYYY_MM_DD.db naming 2026-06-19 07:34:31 -04:00
.gitignore Initial commit: HSA receipt tracker 2026-06-17 21:40:12 -04:00
call_claude.sh Initial commit: HSA receipt tracker 2026-06-17 21:40:12 -04:00
CHANGELOG.md Add deploy docs (CICD + Authelia/OIDC); changelog 0.1.0 2026-06-20 21:20:08 -04:00
config.json Initial commit: HSA receipt tracker 2026-06-17 21:40:12 -04:00
DESIGN.md AI classifier correction notes + misread review (AI tab) 2026-06-20 16:04:30 -04:00
go.mod Normalize receipt image orientation from EXIF; add changelog (0.0.1) 2026-06-19 20:26:03 -04:00
go.sum Normalize receipt image orientation from EXIF; add changelog (0.0.1) 2026-06-19 20:26:03 -04:00
plan.md Initial commit: HSA receipt tracker 2026-06-17 21:40:12 -04:00
README.md Add deploy docs (CICD + Authelia/OIDC); changelog 0.1.0 2026-06-20 21:20:08 -04:00
secret.md Initial commit: HSA receipt tracker 2026-06-17 21:40:12 -04:00
secret.sh Initial commit: HSA receipt tracker 2026-06-17 21:40:12 -04:00
SPEC.md Security hardening: server-side session expiry + nosniff on files 2026-06-20 20:56:38 -04:00

HSA Receipt Tracker

A small, mobile-first web app for two household users to capture and archive HSA-eligible receipts (photo or PDF) for future reimbursement and tax substantiation, with optional AI auto-fill of the amount/date/category/patient.

  • What it does (current behavior): SPEC.md — the source of truth.
  • Why it's built this way (history & rationale): DESIGN.md.
  • Version log: CHANGELOG.md.

Running

It's a single static Go binary (CGO_ENABLED=0, pure-Go SQLite). Configure via environment (see .env.example); ./scripts/build.sh builds it and ./scripts/run.sh runs it locally.

Deployment:

  • deploy/CICD.md — what each git push/tag triggers (branch = build+test; release tag X.Y.Z = build+deploy; pre-release tag = build+stage).
  • deploy/INSTALL.md — one-time host setup, on-disk layout, manual deploy, and rollback.
  • deploy/AUTH.md — the Authelia (OIDC) integration: which config fields must agree with which app env vars, and how access is granted/revoked.

AI classifier correction notes

When an API key is configured, each upload is read by the model to pre-fill the form. You can steer it with correction notes — free-text rules appended to the classifier prompt — managed under the AI tab. When the model misreads a receipt, that upload is recorded; the AI tab lets you review misreads one by one and attribute which note fixed each.

Notes live only in the database (private, never committed, included in /export/db backups). On first run the table is seeded once with these default notes (no PII), which you can edit or delete:

  1. Amounts that use a comma as the decimal separator (e.g. "12,50") mean 12.50, not 1250.
  2. When both a service/visit date and a separate statement, print, or due date appear, use the service date.
  3. "Patient Pay", "You Paid", "Amount Due", and "Patient Responsibility" are the amount actually paid — prefer them over subtotals or insurance-covered amounts.

These defaults are defined in code (internal/storage/ai_notes.go); this list is the human-readable copy. They are only seeded when the notes table is empty, so a deleted default does not come back on restart.