Target interaction specification

BI

Is operating cash actually covering the business, and which transactions make that statement true?

BI may summarize and classify cash movement, but every total must remain traceable to source rows. Funding and internal transfers must not masquerade as operating performance, and corrections must be reversible without destroying the imported record.

Case-study thesis

What the finished product should prove.

This is the behavior to build toward. The implementation receipts below remain the record of what exists today.

A dashboard becomes interaction design when a conclusion can be questioned, opened, corrected, and recomputed without losing provenance.

State model

The interface has to make these states real.

If two states would look identical to the person, the implementation is not finished.

01

Empty

No company data is loaded. The interface explains what input it accepts without showing fake certainty.

02

Importing

Rows are being parsed and the person can see progress, rejection count, and source file.

03

Needs review

Unknown formats, duplicate rows, or ambiguous classifications are isolated before they affect a conclusion.

04

Classified

Each transaction has an explicit business, funding, internal, or unresolved status.

05

Summary

Coverage, runway, and vendor movement are visible with the basis and time window attached.

06

Drilldown

Opening any total reveals exactly the contributing rows and classification logic.

07

Corrected

A person can override a classification, see the summary change, and still recover the original state.

08

Unsupported

A file or currency the parser cannot safely normalize fails loudly before entering the model.

Edge cases

The boring failures are part of the product.

  • The same CSV is imported twice
  • A malformed row is surrounded by otherwise valid rows
  • A transaction could plausibly be funding or revenue
  • Multiple currencies appear in one period
  • A vendor name changes while the underlying supplier is the same
  • A correction changes an earlier month and therefore runway
  • The underlying source file is removed after analysis

Definition of done

The future case study needs these receipts.

  • Clicking any headline metric opens the complete set of rows that produced it
  • Reclassifying one row visibly recomputes all affected summaries and can be undone
  • Duplicate import detection prevents the same movement from being counted twice
  • Unresolved rows are visibly excluded or flagged rather than silently forced into a class
  • The public demo can reproduce expected totals from fixtures without exposing private financial data
HAAM-produkter

HAAM produktutgave · What actually moved

BI

I needed to see whether the work was covering the life around it. HAAM BI reads supported bank CSVs, separates owner funding from operating cash, and shows coverage, runway, and vendor drift. The public host uses a synthetic Northwind set so a visitor can see the shape without anyone’s books.

HAAM BI Northwind demo with cashflow cards and monthly charts.
Rows that make the totalNorthwind on the public host

classes

3

business, funding, and internal. Owner money in is not treated as operating performance.

supported input

CSV

Estonian bank and Wise exports, parsed against a fixture company in tests.

basis

Cash

Coverage, runway, and vendor drift from movement. Not accrual P&L.

uploads on the host

0

bi.haam.co serves Northwind Demo. Owner CSVs stay on the machine in the local app.

The job

Trust the totals, then open the rows.

Bank exports mix funding, transfers, and operating spend. I needed totals I could drill into, with owner money and internal movement kept separable from the operating picture.

The public host had to be visitable without becoming a place where real books sit. Northwind Demo is that set. The parsers and classification rules are the same ones the local app uses.

Open banking, tax filing, and multi-company SaaS were never this pass.

Reading the month

Import. Classify. See coverage. Open the contributing rows.

A highlight that cannot open into transactions is decoration. The fixture totals exist so a reviewer can check the arithmetic.

01

Parse the export

Supported Estonian bank and Wise CSVs become normalized rows. Malformed lines are counted as rejected. Unsupported formats throw.

02

Separate the money

Classification rules mark funding, internal transfers, and business movement. Own-company accounts and the Wise account stay identifiable.

03

Read coverage and runway

Monthly and yearly summaries show inflow, outflow, and whether operating cash is covering the period. Vendor drift sits next to the spend.

04

Open the rows

A total has to name the transactions that made it. Duplicate keys are detected. Optional browser corrections stay local.

Design decisions

What had to stay true in the interface.

bi.haam.co

Classification

Owner funding is labelled before it can look like revenue.

The first lie a cash dashboard can tell is mixing recapitalisation with customers. I kept funding and internal transfers visible as their own classes so the operating net stays readable.

  • business, funding, and internal as first-class labels
  • Own-company and Wise account IDs in the fixture company
  • Travel outflow kept visible inside the month

Evidence

A fixture company the totals have to survive.

expected-totals.json is there so a reviewer can rerun the suite and see the same numbers. Personal paths and live IBANs are out of the defaults.

  • Parser, classification, duplicates, and corrections in tests
  • Fixture CSVs instead of a production dump in Git
  • PAID_COMPANIES.md gitignored

Public host

Show the shape without taking anyone’s file.

bi.haam.co is the same interface over synthetic Northwind data. There are no uploads on that host. The local app remains the place where owner CSVs are read.

  • Northwind Demo on the public URL
  • No bank connection and no tax product
  • Cash movement is not presented as accounting advice

The working stack

What actually runs.

Rules

lib/accounting.ts

Normalization, classification, monthly accumulation, and the path from CSV rows to dashboard data.

Insights

Coverage and runway

computeRunway, vendorDrift, and duplicate detection sit next to the classified rows.

Fixtures

Synthetic company

Expected totals in tests. The public host uses Northwind Demo.

Host

bi.haam.co

Vercel. Local-first for owner files; demo set for visitors.

In evidence

What a reviewer can check.

01Funding, transfers, and operating cash stay separable in the totals

02A reviewer can check fixture totals without seeing a real company

03Unsupported formats fail loudly instead of silently skewing a month

04The public host can be opened without uploading a bank file

Where it stops

The demo set is the public evidence.

There is no bank connection, no tax product, and no native import loop in this pass. I have not recorded a full browser import e2e or an accessibility audit.

Personal use of an earlier dirty tree is not evidence in Git. Accrual P&L and audited books are out of scope.

HAAM’s role

I needed the month to tell the truth about cash.

Coverage statement, cash-basis limit, funding versus business split, parsers, fixtures, tests, and path sanitization. Direct work, 2026.

How we learned

Research

Self-observation + data validation

The dashboard began with a recurring personal question: is the work covering the life around it?

Research came from the structure of real cash movement and the mistakes a dashboard can make when funding, transfers, and operating activity are mixed together. Synthetic fixtures and expected totals then turned those observations into something that could be checked repeatedly without publishing private financial data.

  • Cashflow observation
  • CSV fixtures
  • Classification tests
  • Totals validation

Help improve this website?

Optional analytics. Google Analytics and Clarity load only if allowed; form, email, and chat content are excluded.