Skip to content
Menu
All work

Own productPrivate

Invoices in, reconciled books out

Our own property finance system. Claude reads invoices into a validated ledger, and the site refuses to build if the books don't add up.

Industry
Property and finance
What it shows
AI document extraction, Finance dashboards, Data quality
Year
2026
Status
Private
Finance HubDashboardExpensesPurchasesWorksAnnual summaryRentIncomeSaved · no conflictsDummy data€18,400Income this year€6,950Expenses this year€11,450Net this yearIncome and expenses by monthIncomeExpenses€0€1k€2kJanFebMarAprMayJunJulAugSepLatest batchClaude reads each new document; intake checks its fingerprint firstDOCUMENTSHA-256INTAKERESULT2026-09-17_supplier-a_inv_flat-a.pdf9f2c…e41aNewClaude booked 4 lines, archived2026-09-18_supplier-b_inv_flat-b.pdf3b07…91cdNewPayer unclear: asked the ownerscan_0918.pdf9f2c…e41aDuplicateSame SHA-256 as an archived file, skipped2026-09-19_supplier-c_rcpt_parking.jpgc4d1…07abRe-scanReplaces an earlier copy, marked supersededOriginals are append-only. Every save copies the previous state first.Books check52 checks passed · build openCSV shapecolumns and row widthsIDsunique, well formed, no gapsExpense rowsnet + VAT = total, splits add upMirror and seedapp rows tie to the booksLine itemsderived from the CSV, no hand editsDocument storeSHA-256 matches, append-onlyAssetsequipment ties to its invoiceLedgerstated total equals computedSelf-testPlants one mistake at a time in a copy of the books:wrong flat, shifted split, a byte added to an original …8 of 8 planted mistakes caught47 originals · 207 line itemsdaily backups kept 30 days
Recreated with dummy figures, documents and fingerprints. The checks, counts and workflow are the real system's; the books stay private.

In numbers

source documents archived, each with a fingerprint
47
ledger line items booked from those documents
207
validator checks the books must pass before the site builds
52
kinds of planted mistake the self-test proves are caught
8

Figures come from the project’s own files and records.

What changes

The steps people did by hand, and the route the work takes now.

A supplier invoice arrives

Before

  1. Open the PDF
  2. Retype every line into the ledger
  3. File the original
  4. Check the totals at month end

With AI

  1. Claude reads it and books every line
  2. A validator and build gate check the books

Books reconcile, every entry traceable

The problem

A small holding company with two flats and a parking space still produces a steady stream of paperwork: purchase and renovation invoices, rent, maintenance, and tax at the end of the year. Spreadsheets drift, receipts go missing, and the question “what did this property actually earn?” takes an afternoon to answer.

What we built

A private finance system with a dashboard for income, expenses, rent status, maintenance and the tax summary, plus a bookkeeping workflow behind it. Invoices go into an inbox. Claude, following a written bookkeeping procedure, reads each one, books every line into the ledger and files the original with a fingerprint so it can be traced later.

AI where it helps, rules where it matters

The AI does the tedious part: reading documents in any layout and typing them up. It does not get the final word. Every booking passes a validator, a self-test proves the validator still works, and the build stops if anything fails. Money is summed in whole cents, so rounding can’t creep in.

There are no AI calls at runtime. The dashboard only shows data that has already passed the checks.

Inside the checks

Open the system map of every part, follow one dummy invoice from the inbox to the dashboard, open the validator’s eight groups, or run the self-test that plants mistakes to prove they are caught.

Interactive · 8 journeys

Interactive system map

Every part of Finance Hub, and how they connect

29 parts and 8 journeys, from a document in the inbox to the dashboard, the checks and the backups. Checked against the code on 12 October 2026.

Play 8 journeys, or click any of its 29 parts.

checks the books must pass
52
self-test cases: a clean copy and 8 planted mistakes
9
source documents archived, each with a SHA-256
47

Explore the map

InteractiveFollow an invoice step by step, open the checks, or run the self-test.
View
Step
Step 1 of 7

Inbox

An invoice lands in the inbox folder, in any layout and under any name. Nothing has read it yet, and nothing in the books has changed.
  1. Invoices and receipts all go to one folder.
  2. PDFs, photos and scans are all fine.
inbox/
scan_0917.pdf1.4 MB
FromSupplier A
InvoiceA-0917
Lines4
Total€107.69
What a person would see on the page. The system has not read any of it yet.
Step 2 of 7

Intake

Intake fingerprints each inbox file with SHA-256 and checks the register before anything is read. It only reads: it moves and changes nothing.
Try a different file
Filescan_0917.pdf
Size1.4 MB, under the 5 MB flag
SHA-256
9f2c4b7e01d35a8c6e29f0b4d7a13c58e6f20b9d4a7c13e58f02b6d9a4c7e41a
Register says
New
No archived file has this content or this name. It goes on to Claude.
Filescan_0917 (1).pdf
Size1.4 MB, under the 5 MB flag
SHA-256
9f2c4b7e01d35a8c6e29f0b4d7a13c58e6f20b9d4a7c13e58f02b6d9a4c7e41a
Register says
Duplicate
Same fingerprint as 2026-09-17_supplier-a_A-0917_paint_flat-a.pdf, already archived. Skipped: nothing is read or booked twice.
File2026-09-17_supplier-a_A-0917_paint_flat-a.pdf
Size1.4 MB, under the 5 MB flag
SHA-256
3b07d1e5a9c2f4086b1de73a5c90f2d4e81b6a7c3f5d09e2b4a6c8d1f37091cd
Register says
Name match
Same name as an archived file, different content: a re-scan. It waits for a supersession decision before anything is booked.
Step 3 of 7

Claude reads

Claude reads each new file and appends rows to the books: supplier, dates, VAT and every line item. When something is unclear it asks the owner instead of guessing.
Who paid?
  1. Book what was actually paid, gross.
  2. Mark cash only when the document says so.
  3. Payer unknown: book it as TBC and ask.
  4. Corrections are new rows or status changes, never deletions.
SupplierSupplier A
InvoiceA-0917
Date2026-09-17
PropertyFlat A
Paid byCard
PayerCompanyTBC
  1. Wall paint, 10 l × 2
    49.00 + 10.29 = 59.29
  2. Primer, 5 l
    18.00 + 3.78 = 21.78
  3. Brush and roller set
    12.00 + 2.52 = 14.52
  4. Masking tape × 4
    10.00 + 2.10 = 12.10
  5. Invoice, net + VAT = total
    89.00 + 18.69 = 107.69
Net + VAT = total on every line and for the invoice, to the cent.
Open questions
2026-09-17
Who paid Supplier A invoice A-0917? The document does not say.
Booked with payer TBC, not guessed. The owner’s answer is recorded with a date, and the row’s status changes. Some decisions are locked in code so they cannot drift later.
Step 4 of 7

Archive

The original is filed under a strict name, and the copy is proved exact before the inbox file is moved. Nothing is deleted.
  1. Comes from the inbox
    Archive accepts inbox files only.
  2. Name follows the pattern
    YYYY-MM-DD_supplier_docnumber_subject_property.ext
    2026-09-17_supplier-a_A-0917_paint_flat-a.pdf
  3. Content not archived before
    Already archived content is refused.
  4. Copy re-hashed
    The copy’s SHA-256 equals the original’s, so it is byte-identical.
    9f2c4b7e…a4c7e41a=9f2c4b7e…a4c7e41a
  5. Inbox file moved
    To _processed/2026-09-17/, kept, never deleted.
Step 5 of 7

Validate

The derived files are rebuilt from the books, then the validator runs all 52 checks. The batch goes in as one commit, then a backup is taken.
  1. Daily backups, kept 30 days.
52 of 52 checks pass
  1. CSV shape
  2. IDs
  3. Expense rows
  4. Mirror and seed
  5. Line items
  6. Document store
  7. Assets
  8. Ledger
Rebuilt: line items JSON, app seed1 commitBackup taken
Step 6 of 7

Build gate

The app only builds if every stage passes, and CI runs the same gate. A last check scans the finished bundle so no bookkeeping detail reaches the public code.
  1. When books files are staged, a pre-commit hook refuses unstaged edits and runs the checks again.
  1. 1LintPass
  2. 2Books check · 52 checksPass
  3. 3Self-test · 9 casesPass
  4. 4Server testsPass
  5. 5Unit testsPass
  6. 6BuildPass
  7. 7Dist checkFails the build if any of 6 leak patterns appear in the public bundle: line-item IDs, the unit cost field, books row IDs or invoice numbers.0 found
Step 7 of 7

Dashboard

The booking appears in the app. There are no AI calls at runtime: the app only shows data that has already passed the checks.
  1. Saves carry a revision token. A stale save gets a conflict, and the person chooses Discard mine or Merge.
  2. A guard refuses any save that would make a stored record disappear. Deletes are soft.
  3. The previous state is copied before every overwrite. The audit log is append-only, and deleted items can be restored.
The app’s 7 views:DashboardExpensesPurchasesWorksAnnual summaryRentIncome
Supplier A€107.69
2026-09-17Flat ARepairsCardPayer: companyPayer TBC, question open
4 line items · net 89.00 · VAT 18.69
Saved, no conflicts
52checks in 8 groups
The books must pass all of them before the app builds. Open a group to see what it covers.
  1. 1CSV shapeColumns and row widths
    1. Each file has the expected number of columns
    2. Every row is as wide as the header
  2. 2IDsUnique, well formed, no gaps
    1. IDs are unique
    2. IDs are well formed
    3. No gaps in the sequence
  3. 3Expense rowsNet + VAT = total, splits add up
    1. Dates are ISO, YYYY-MM-DD
    2. The property is a valid one
    3. Net + VAT = total
    4. Net and VAT are both present or both blank
    5. The split across assets adds up to the total
    6. A non-cash row has a source document
    7. Fields with a fixed list hold a value from it
    The self-test plants here: a typo in a value from a fixed list.
  4. 4Mirror and seedApp rows tie to the books
    1. App rows tie to the books
    2. The grand total ties
    3. Each row sits on the right asset
    4. Amounts match, within 1 cent on odd splits
    5. Dates match
    6. Categories match
    7. A locked owner decision is enforced
    The self-test plants here: a cost booked to the wrong flat in the app mirror; a 50/50 split shifted; a stale seed; a cost moved to the wrong flat column in the CSV; a locked owner decision broken.
  5. 5Line itemsDerived from the CSV, no hand edits
    1. The JSON is exactly derived from the CSV, with no hand edits
    2. Invoice and quantity match
    3. Discount arithmetic is right
    4. Each document’s lines sum to its total
    The self-test plants here: a hand-edited line-items file.
  6. 6Document storeSHA-256 matches, append-only
    1. Status is an allowed value
    2. The file exists
    3. Its SHA-256 matches the register
    4. No two files share the same content
    5. No unregistered files
    6. Superseded copies are marked
    7. Originals are append-only, checked against git
    8. Every source document resolves to a file
    The self-test plants here: one byte appended to an original.
  7. 7AssetsEquipment ties to its invoice
    1. Equipment net amounts sum to their invoice
    2. Serial numbers are unique
  8. 8LedgerStated total equals computed
    1. The header date is not older than the newest change
    2. The stated grand total equals the computed one

Does the validator still catch mistakes?

The self-test copies the books to a temp folder and plants one defect at a time. Each time it runs the 52 checks and expects the right group to fail. A clean copy must pass.
  1. 1Nothing planted: a clean copyAll groups passPasses
  2. 2A cost booked to the wrong flat in the app mirrorCaught by Mirror and seedCaught
  3. 3A 50/50 split shiftedCaught by Mirror and seedCaught
  4. 4A hand-edited line-items fileCaught by Line itemsCaught
  5. 5One byte appended to an originalCaught by Document storeCaught
  6. 6A stale seedCaught by Mirror and seedCaught
  7. 7A cost moved to the wrong flat column in the CSVCaught by Mirror and seedCaught
  8. 8A locked owner decision brokenCaught by Mirror and seedCaught
  9. 9A typo in a value from a fixed listCaught by Expense rowsCaught
The clean copy passes. 8 of 8 planted defects caught.
Dummy figures and documents. The checks, counts and workflow are the real system’s, and the system map and its numbers were checked against the code on12 October 2026.

What it shows

Most finance teams have the same problem at larger scale: documents arrive in every format, someone retypes them, and errors surface at month end. The pattern here, AI extraction behind strict validation and a clear audit trail, carries straight over to accounts payable, expense claims and supplier onboarding.

Under the hood

  • Claude skill
  • React
  • Vite
  • Netlify Functions
  • Netlify Blobs
  • recharts
  1. 01Inbox

    Invoices and receipts land in one folder, in any format. Intake fingerprints each file and sorts it as new, a duplicate or a re-scan before anything is read.

  2. 02Claude reads

    A Claude skill extracts supplier, dates, VAT and every line item into the ledger, and archives the original with a fingerprint.

  3. 03Validation

    52 checks in eight groups, from net plus VAT equalling the total to every original matching its SHA-256. A self-test plants eight kinds of mistake in a copy of the books to prove each one is caught.

  4. 04Build gate

    The site will not build if the books fail, or if any bookkeeping data would leak into the public code.

  5. 05App

    A dashboard for income, expenses, rent, maintenance and tax. Saves are checked for conflicts, and nothing is ever silently deleted.

  6. 06Backups

    A scheduled job keeps a daily copy of the app for 30 days, every save keeps the previous state first, and the books get an add-only off-site copy.

Want something like this built for your team?

Tell us about the process or the data. We'll reply within two business days with a first view of what we'd build.