Case study · Internal product
↳ Stakeholder · Product · UX · UI

We fired our accounting
software, and built our
own
instead.

MonoDo is a native macOS/iOS invoicing and light-accounting app built for kreido s.r.o. — designed end to end by its own product designer and shipped through daily pair-programming with an AI teammate, not a dev team.

SoloProduct · UX · UI
SwiftUI · SwiftDataPlatform
macOS + iOSNative, no web view
~4 weeksZero to daily use
↳ 01 — Context

The old tool worked. It just didn't work for us.

Before MonoDo, kreido s.r.o. ran on Totals — a solid, general-purpose invoicing app. It handled the paperwork. What it couldn't do was grow with a studio that also tracks time, watches its own cashflow, and needs a Slovak KV DPH file at the end of every quarter without three extra spreadsheets stitched together by hand.

The brief was never "build an app." It was "stop losing an afternoon a month to reconciling four tools." Building turned out to be the fastest way to say yes to that.

↳ 02 — Stakeholders

Four people use this product. Three of them are the same person.

A single-founder studio still has real, distinct stakeholders — they just share a body. Designing for each of them separately kept the product honest about who a given screen was actually for.

Owner

The invoicer

Needs a faktúra out the door in under a minute, correct VAT, correct numbering, no thinking required.

Owner

The bookkeeper

Needs KV DPH, SV DPH and a year-end P&L that an actual accountant can accept without translation.

Owner

The freelancer running it

Needs to know, this week, who owes them money and who they owe — not next quarter when it's a problem.

External

The client receiving the invoice

Never opens the app. Judges the whole product on one PDF: does it look right, is the IBAN correct, is it in Slovak.

The best interview subject for this product was six months of my own bank statement.

↳ 03 — Product strategy

One ledger, not five apps glued together

The scoping decision that shaped everything else: invoicing, time tracking, expenses and compliance reporting live in one data model, so a paid invoice, a logged hour and a VAT return are three views of the same facts — never three copies that can drift apart.

Sell
Quotes → Orders → Invoices → Credit notes
Track
Projects → Tasks → Time entries
Spend
Expenses, assets, licences, loans, insurance
Drive
Vehicle logbook, business trips
Comply
KV DPH / SV DPH XML, year-end summary
Reconcile
Bank statement import, auto payment matching

Every module answers the same test: does this fact need to reappear somewhere else without being retyped? Logged time becomes an invoice line. An unpaid invoice becomes a Saldokonto row. A paid invoice becomes a KV DPH line. Nothing is entered twice.

↳ 04 — UX principles

Designed for someone who isn't an accountant

The primary user has never filed a tax return and shouldn't have to learn to. Three rules did most of the work:

01Say the tax term once, in context

Never make it the label

Fields are named the way a designer thinks ("VAT rate", "Deductible"), and the compliance vocabulary (KV DPH, SV DPH, § 43) only shows up on the export screens that actually need it.

02The dangerous action explains itself

Before it happens

Deleting a workspace requires typing its name back. Switching companies mid-import is caught and the write is silently discarded rather than landing in the wrong ledger. Nothing destructive is one click from "browsing."

03State should be true

Not just labelled

A "Paid" badge used to mean someone clicked a button. It now always means a real payment record exists — Saldokonto and the badge can never disagree, because they read the same fact.

↳ 05 — Interface

What it looks like

Dark by default, information-dense, built for someone scanning between two monitors rather than reading a brochure. Four representative screens below.

MonoDo — Invoices
Dashboard
Time
Sales
Invoices
Quotes
Clients
Expenses
Expenses
FA2026009 · TV LUX, s.r.o.Sent
FA2026008 · CoolPeople s.r.o.Paid
FA2026007 · Q7 digital mediaOverdue
FA2026006 · ITnet s.r.o.Paid
Invoice list. Status is computed, not typed — "Overdue" flips itself the moment a due date passes, so the badge and the aging report can't quietly disagree.
MonoDo — Time
Client website
↳ Design
↳ UX
↳ UI
Internal app
↳ Backend
Today
3:42
Billable
3:10
Entries
6
Homepage wireframes · Design1:15
Client feedback · UX0:40
Time tracking. Project → Task → entry. A task ("Design") is just a second level of the same tree a project already was — added later without disturbing a single existing log.
MonoDo — Aging
Receivables
Payables
Not yet due
€1,240
1–30 days
€860
90+ days
€0
Q7 digital media s.r.o. · 1 invoice€860 · 14 days
MEMO 98 · 1 invoice€1,240
Aging report. One toggle switches from what clients owe the studio to what the studio owes suppliers — the same aging-bucket logic reused instead of a second report invented from scratch.
↳ 06 — Process

Design in production, not before it

There was no separate Figma phase. Every screen above started as a real SwiftUI view, tested against real invoices and a real bank statement from day one — the fastest feedback loop available was "does this number match my actual balance."

A bug that only shows up in six months of real invoices is worth more than a week of Figma review.

That production-first approach surfaced problems a mockup never would have:

01

The "Paid" badge that lied

Marking an invoice paid changed a label but never recorded a payment. Saldokonto — reading the real payment ledger — kept showing settled invoices as debt. Found by comparing the app's own numbers against the actual bank balance, not by testing the button.

02

The phantom gap

A nested split-view layout left a silent empty column between a list and its detail pane on macOS — invisible in a mockup, obvious the first time a real screen was screenshotted mid-review.

03

Import that quietly dropped addresses

The prior tool stored client addresses in a separate table the import never joined against. Twelve real clients imported with names and nothing else — caught only because the destination screen was checked against source data, not the import log.

↳ 07 — Reflection

What "product designer" meant here

Building the tool you'll use yourself, tomorrow, for a real invoice, removes every layer of proxy research a normal engagement needs. The trade is that there's no one else to blame for a bad decision — and no one else to catch one either, which is exactly why every dangerous action in MonoDo explains itself before it runs.

More work
Back to case studies
View all →
↳ Contact

Let's talk.

A specific problem, or just a second opinion — reach out. For enterprises and growing teams alike.

© 2026 · krei.do — Strategic Product Design PartnerPrivacy policySK · EMEA
Founder: Tomáš HudákLinkedInwebsite