1. Enforce the 12h session lifetime server-side in requireAuth (reject a
session older than the TTL even if the sealed cookie is intact), so a
leaked cookie value can't be replayed indefinitely. Shared sessionTTL
const drives both the cookie MaxAge and the check.
2. Send X-Content-Type-Options: nosniff when serving user-uploaded
receipt/attachment bytes, so the browser won't sniff past the declared
(upload-time allowlisted) MIME type.
Update SPEC §2 and §6 accordingly; tests cover stale-session rejection.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the single-line note inputs (which truncated long notes) with
wrapping, auto-growing textareas and a per-note Save/Delete row, so the
whole correction note is readable and editable. Changelog 0.0.4.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a global, temporal ai_notes list appended to the classifier prompt
(seeded once from no-PII defaults, documented in README), managed inline
on a new AI tab with a read-only view of the assembled prompt. Every
AI-run upload records the browser-round-tripped suggestion blob + model;
misreads are derived (final field != AI guess) and reviewed one by one
(image + per-field guess-vs-entered + notes-since), attributing which
note fixed each or closing unresolved. Update SPEC (new section 10),
DESIGN item 15, README, and changelog (0.0.3).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a shared, free-form tag vocabulary attachable to a receipt at upload.
New tags/receipt_tags tables (case-insensitive label dedup); an in-page
chip-mosaic picker after "Who" with inline tag creation. Tags are
resolved/created only on successful submit, and shown on the confirm
page and recent lists. Documented as spec item 14.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Bake the EXIF Orientation rotation into uploaded JPEG pixels (and strip
the tag) so receipts are upright in every consumer, not just EXIF-aware
viewers. Acts only when orientation is known (tag 2..8); images with no
tag, tag 1, non-JPEG, or PDFs pass through byte-for-byte. Wired into the
receipt, attachments, and AI-classify paths. Documented as spec item 13.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Abbreviate "First Last" → "F. Last" in the recent list and nowrap the upload
timestamp, so rows fit on narrow phone screens instead of wrapping.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Drop the (usually garbage) original filename. Each row is now a single line:
amount link · date · category · who, attachments as 📎 links (filename on hover),
and a small muted upload time.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Open() now runs PRAGMA quick_check after WAL recovery. WAL mode already makes
opening self-healing (committed writes rolled forward, an interrupted write
discarded), so a crash mid-write recovers automatically; quick_check fails fast
only on genuine corruption, pointing the operator at BACKUP_DIR.
- spec item 12 documents the durability/recovery model and the orphan-file caveat.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Backup dir default ./data/dbbackup; files named hsa_sqlite_backup_<YYYY_MM_DD>.db
(one per day; a same-day re-run is a no-op since the dated file exists).
- Simplify the scheduler: attempt on start, then tick every BACKUP_INTERVAL.
Per-day idempotency makes restarts and sub-day intervals settle at one/day —
removes the date-parsing untilNext/newestBackup logic (and its busy-loop edge).
- BACKUP_INTERVAL remains the frequency knob (Go duration; 0 disables).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- internal/backup: weekly (configurable) snapshots via the existing VACUUM INTO
+ blob-strip path; restart-safe (only backs up if newest is older than the
interval), retains BACKUP_KEEP most recent, prunes the rest. Runs in a
background goroutine; failures are logged, never fatal.
- Config: BACKUP_DIR (./data/backups), BACKUP_INTERVAL (168h; 0 disables),
BACKUP_KEEP (8).
- Fix: blob-strip now clears attachments.image_data too, not just receipts.
- Fix: STORAGE_DIR is the storage ROOT (default ./data) — receipts/ and
attachments/ live under it; corrects the doubled-nesting from item 10.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- New attachments table (FK to receipts), dual-write: file on disk + DB blob.
- On-disk layout split: receipts under <ROOT>/receipts/<YYYY>/..., attachments
under <ROOT>/attachments/<YYYY>/..., attachments named from the parent
receipt's date+amount stem (_att, _att_1, ...).
- Upload form gains an optional multi-file "Additional files" field; the files
ride along with POST /upload, saved after the receipt row exists. No AI runs
on attachments; primary-image auto-fill unchanged.
- GET /attachment/{id}/file serves blobs; confirm page lists them; recent list
links them. Adding attachments to an already-saved receipt is not yet supported.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace flat UUID filenames with a browsable, dated layout (spec.md item 9):
<STORAGE_DIR>/<YYYY>/<MM>_<DD>_<dollars>.<cents><ext>, from the receipt date
and amount. Same date+amount collisions get a _1, _2, … suffix via exclusive
create (race-safe). New uploads only; serving is unaffected (blob-backed).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Features (see spec.md v2):
- Wire receipt classification into the upload flow; cheap model (Haiku 4.5)
is now the default, shown as a footnote with per-scan cost in cents.
- Skip-AI toggle to enter fields by hand.
- Duplicate-transaction warning: live check on date+amount, gated submit.
- Tally tab: person x year totals with margins and grand total.
- Recent uploads / recent receipts tabs with paging and file serving.
- People reconcile on startup: merge stray partial names (e.g. "Jude" ->
"Jude Tremblay"), reassigning receipts; idempotent seeding.
- scripts/build.sh builds the binary; scripts/run.sh builds and runs with .env.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Go app for capturing and archiving HSA-eligible receipts: OIDC/PKCE auth
against Authelia, SQLite storage with dual-write (filesystem + DB blob),
mobile-first upload, and DB export.
Adds AI receipt classification: a config.json catalog of people and
categories (seeded into the DB on startup), a prompt builder that derives
name-order/initial variants from the data (with same-surname ambiguity
handling), and an Anthropic tool-use client behind POST /classify. Tests
run against a mock endpoint; a live integration test is env-gated to the
cheapest model.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>