Where Money Docs

Using the app

Import

One gesture, and nothing is written until you commit. The guided setup for a new bank is Your first import; it stays available as Set up another bank….

Drop a file#

Drop a CSV on the tab, or click to browse. The app reads the layout off the file itself — a bank it has seen before is recognized by its shape, a new one is worked out on the spot — and picks the account too, when the file carries a number of one you have. With both settled, the rows stage straight onto the review screen; the only question the tab ever asks is the account, when the file doesn't answer it.

Under Advanced there is a per-file skip rows override, for when a bank changes the length of its junk preamble between exports. The remembered layout is not changed.

The review screen#

The head#

Under the file name, the head says how the rows were read — known layout for a shape seen before, or the three columns the reading chose for a new one — with adjust beside it, which opens the mapper on this very file and re-stages with your corrections.

Seven counts, each also a filter, on the same line as the title:

BucketMeaning
parsedRows the layout understood
will commitWhat the button writes
categorizedOf those, how many a rule or you have placed
uncategorizedThe rest, including rows a never-match term blocked
parse errorsRows that failed. Never written; their text is kept
duplicatesAlready in the database. Never written twice
skipped by youRows you excluded

Beside the buckets, a pill gives what the rows in view add up to — the question a filter raises. When the layout maps a balance column, the head also reports balance continuous · 1 240,00 → 3 981,55 — or balance not checked, when this particular export doesn't carry the column the layout names.

Banners#

The screen warns before it writes:

  • This exact file was already imported — matched by hash. If it went to a different account last time, it says so: fingerprints are per account, so nothing would dedupe.
  • This file never mentions X's account number, but it does mention Y — a button re-stages into the right account without starting over.
  • The running balance breaks at line 88 — a row is missing, doubled or parsed wrong.
  • N rows need an NBP rate that is not fetched yet — the commit stays blocked, and a button fetches exactly the missing range. See Currencies.

Rows#

Each row shows its state and its category. A row a rule claimed prints the term it matched beside the chip — «BIEDRONKA», and the full line (kw «BIEDRONKA» · p20) on hover: in a column the answer to why is this Groceries is the word, and kw reads the same on every row that has one. A row nothing claimed prints nothing: no rule matched on a hundred rows was a hundred lines saying that nothing happened, and the Uncategorized chip already says it.

A parse error appears in the cell that caused it, with the value and the message, so you can see that a date column contained n/a rather than just being told the row failed.

Every committable row carries a bar down its left edge — amber while it still needs a human, accent once it is answered — so the left of the table reads as progress.

Clicking a row puts it in the dock, and does nothing else.

The dock#

A hundred uncategorized rows are not a hundred decisions. They are maybe fifteen shops — so the keyword is the lever, and the only real question is how far it reaches. The dock under the table asks that first and assigns second.

Scope: what a commit will touch#

Three answers, one segmented control, and the rows it covers are highlighted in the table above it while you read it.

  • this row — the one you are on.
  • matching «…» — every row the keyword reaches that still has no category. A row a rule or you already placed is left alone, so the count is exactly what the button will move.
  • selected — the ticked rows. Ticking any row switches to this on its own; unticking the last one hands the scope back to the row you are reading.

The keyword#

Mined off the row and editable in place. Beside it, the rows it would assign; the try chips are the other words the row offers, each carrying how many rows in this file it reaches — which is what stops the two usual mistakes, a rule so specific it will match this one transaction forever, and one so broad it swallows three restaurants along with the supermarket. The run of the title a keyword caught is marked on every row it covers.

Under it, always match «…» — the tick that turns the keyword into a standing rule when you commit. It carries the rows the rule reaches, and the button above it counts them in: on this row with the tick off the button says Assign 1 row, and with it on the same button says Assign 10 rows, because that is how many rows the commit changes. Those ten are highlighted in the table too.

The tick arrives ticked when you choose matching and unticked when you choose this row or selected — the scope and the rule are the same question asked at two widths — and it then stays wherever you put it.

When the keyword reaches rows beyond the ones it would assign, a line says both numbers. A ticked batch of unlike rows has no shared keyword, and says so: assignment only.

The category, and the commit#

Every category is on screen at once as a tile, each with its mark, its name and — for the first nine, the most-used — the number key that picks it. Nothing scrolls, so a number key never points at something out of view.

Four ways in, one grid: click a tile, press its number, drag rows onto one, or type in the search box. The number keys do not follow what you have typed — 1–9 stay pinned to their category, so searching never moves a number out from under your finger.

Picking a category does not assign anything. One button does, and it reads the whole decision back: Assign 14 rows → 🛒 Groceries, where the number is everything the commit will move — the scope, plus every row the rule will claim. ⏎ presses it; ⇧⏎ assigns without the rule whatever the tick says, and the button's number is the scope alone again the moment you untick it. A rule written mid-review recategorizes the whole staged batch immediately, so you see the effect before committing, and manual assignments are never overwritten by a rule added afterwards.

The category is a per-row answer, so it does not travel: move to another row and the button goes back to Pick a category. The scope and the tick do travel — they are how you are working, not what this row is.

Under the button, what the last commit did — 5 rows assigned · undo — which stays until you move to another row by hand. undo puts the rows back and takes the rule with them.

The rest are second thoughts, on the line below: save the rule only writes the rule without touching the rows — the answer when these rows are already where they belong and it is the next file you are thinking of. Reset to automatic hands a row you assigned by hand back to the rules. never match puts the keyword on the never-match list instead of a category, which is the right answer for a marketplace that sells everything; it reports itself the same way — «TAXI» will never match again · undo — and the undo lifts the term and gives every row it blocked back.

Assigning moves you to the next row that still needs a category, keeping the scope and the tick. That is the loop: read the next keyword, press its number, ⏎.

Making a category here#

Type a name no category carries and the tile grid gives way to a create form — ⌥N opens it over a grid that still had matches. The search field is the name field, so the name already exists by the time the form appears and its only job is the mark and the keywords: every keyword becomes a contains-rule, each chip carrying the rows in this file it reaches. Its kind is read off the row's sign and its priority is the usual 20; both stay editable on the Categories tab.

Nothing is written until the commit. esc leaves nothing behind.

The record#

▸ Record and ▸ Note open over the table: the parsed fields, the columns the layout ignored, the original CSV line and the fingerprint. They are folds rather than a permanent panel because during assignment the fields being read are the title, the date and the amount — and the dock's own header repeats all three.

Several rows at once#

Every row carries a checkbox. The one in the header ticks every row that still needs a human, which is the batch worth having; ticking anything switches the scope to selected, and the band under the table can skip or restore the lot. space ticks the focused row, shift-click and ⇧↑↓ extend. Full list of keys: Keyboard.

Committing#

Everything goes in one transaction, with duplicate protection enforced again at the database level. The confirmation says how many rows landed and how many were skipped.

Past imports#

Every import ever made, with a needs attention column showing rows still uncategorized or blocked. Clicking a chip opens that import filtered to exactly those rows.

  • edit re-opens its transactions to fix categories. It is the review screen again — same table, same dock, same numbers — except every action writes immediately. x is free here, so it is the never-match key. undo still takes back both the rows and the rule, which is why the commit records which rows the rule caught: once a rule has run, a committed row's provenance cannot tell it apart from one that was always there.
  • delete removes the import and all of its transactions. This is the undo; it asks first.

The original file is kept with each import, so a parser fix can be replayed without going back to your bank.

Where Money is independent software, not connected to any bank, and its figures are not a substitute for your bank's own statements. Privacy, disclaimer & terms.