Storage & export
Receipts that survive a refresh.
Every row and every receipt image lives in this browser's IndexedDB — real Blobs, checksummed at intake and re-verified on every read. One export produces the backup and the Finance handoff as the same file, and importing it anywhere reproduces the report exactly.
What is actually stored, and where
Figures come from navigator.storage.estimate(), not from
adding up what we think we wrote. The indicator in the header reads the
same source.
Integrity
Every attachment row must have bytes behind it, and every original's bytes must still hash to the checksum recorded at upload. This re-reads and re-hashes what is on disk — it does not consult the row it is checking.
Capture into durable storage
This panel does not reset the store — it is the durable session. Add a receipt, reload the page with ⌘R or Ctrl-R, and the image is still here. That is acceptance criterion 1, and it is the one that was broken.
Stored receipts
Thumbnails are generated at intake at 400px so this list never decodes a full-size photo. Open one to read the stored original.
One file, both jobs
The zip is the backup and the Finance handoff. receipts/ plus
the manifest is exactly what replaces the folder the employee used to
attach to an email — same contents, but the names are generated and the
checksums are verifiable, so nobody writes on a receipt to make it
traceable.
—
Never trapped in one browser
Import a previously exported zip. Every row goes back, every receipt is
read out of receipts/ and re-hashed against the manifest
before it is written, and the outcome is reported by
invoice_ref — never a bare “import complete”. Importing the
same zip twice changes nothing: reports match on employee and period,
lines on their reference within it.
One interface, two implementations
Every persistence call in the application goes through the same thirteen
methods. Swapping stores is the storage_adapter setting and
nothing else — no call site knows which one it is talking to.
The interface
| Method | Returns | Notes |
|---|
Object stores
| Store | Key | Indexes | Model table |
|---|
Eleven criteria, executed
Run against a separate database — countryside-expense-acceptance —
so twenty four-megabyte fixtures never land in your real report. The real
configuration is restored when the run finishes.