← Work
Case study · 2025 · Solo - Employed

Legal Ledger

A web app for Swedish law firms that I built at Duobox Legal, mostly on my own, using Lovable and then Claude Code. It handles cases, clients, time logging, documents and invoices.

The job

Legal Ledger is a web app for Swedish law firms. It holds the cases, the clients, the hours, the documents and the invoices, and a firm has it open all day.

I built it at Duobox Legal, where I was effectively the only developer on it for about a year. Another developer did a few smaller pieces. Duobox runs on it, and it's built to work for any firm.

I didn't type most of this code. The first ten months were built in Lovable and the last two in Claude Code, and the design and the technical decisions were mine.

Learning the work

I knew very little about how a law firm runs when I started. I didn't know what a credit invoice was until I built one.

My boss wasn't technical either. A feature usually arrived as a couple of sentences about what he wanted, so most of my time went on the questions those sentences left open. Crediting an invoice is a good example. What does it do to the revenue figures, can a credited invoice still take a payment, what happens when the client has already paid? I read up on it, asked him what he expected, decided, built my reading of it and showed him. Most of the time he was happy with it.

He decided what the product should do, and I decided how it worked.

Logging time and invoicing

The core of the app is one loop. Hours are logged against a case, the hours become an invoice, the invoice goes out, and the payment has to come back to the right invoice.

Swedish rules shape most of it. An invoice carries an OCR or RF reference, which is the number the client types into their bank. Payments are either recorded by hand or synced back automatically from Fortnox, where the firm's accounting lives. Fees and VAT are worked out per case, and one invoice can be split between several lawyers when more than one of them worked the case.

Credit invoices took the most care. A credit is its own invoice record pointing back at the one it credits. It never counts as revenue, so it stays out of every key figure and every report, and it can't receive a payment. An invoice paid past what's left after crediting is marked as overpaid and flagged for someone to check. A mistake there shows up as a firm's revenue being wrong for a quarter.

Demo mode

The decision I'm happiest with is that the app has a second data source. Demo mode is an in-memory store seeded with a fake firm, and you reach it from the sign-in page without an account.

It was there to show the product to a firm without setting anything up for them, and it ended up being what the whole test suite runs against, with no credentials and no database. Every screenshot here is demo mode.

The price is that every piece of data access has two paths, and a feature that only works against the real backend breaks the demo and the tests at once. Nothing in the code catches that, so it stayed a rule I had to enforce.

Making the software look good

Most of the legal software these firms had used looked like it was made in 2005, so being nice to sit in front of all day was part of the product.

The design system is written down in the repo, in two files. One says who the users are and what the product must never look like. The other is the system itself: thin borders and no cards inside cards, very little colour, and money in tabular figures so a column of numbers lines up.

It's written down because AI-built interfaces drift. Left alone, they put everything in a card, give every heading an icon and mute every piece of text.

What enforced it is a skill called impeccable, which reads those two files at the start of every session. I leaned on it heavily. It can score a screen against the system and list what's wrong with it, or work on one thing at a time, like the spacing, the contrast or the empty states. It also runs on every edit to a UI file, so a bad pattern gets caught when it's written.

The app is bilingual, Swedish and English. Swedish words are longer, so every screen has to fit the Swedish text as well as the English.

From Lovable to Claude Code

Lovable was the first tool I used to build anything with AI.

It's very good at getting you moving. You have a working app quickly, and for a long time that was enough. The limits show as the app grows. You work through a browser instead of the repo, small exact changes get harder to ask for, and the loop of prompting, waiting and looking slows down.

I tried Claude Code on a personal project and then moved this over. What changed was the process around it, and most of that came from a plugin called superpowers. A feature starts as a written design document covering the problem, the approach I picked and what it must never do. That becomes a plan of steps small enough to check one at a time, built in slices with testing and review at the end of each. Both documents are committed beside the code, so the reasoning is still there six weeks later.

Neither superpowers nor impeccable comes with the tool, and I'd be a lot slower without either. Finding the right things to put around the model, and learning to use them properly, turned out to be as much of the job as the prompting.

What I took away

Legal Ledger was the first product I was responsible for. There was nobody to hand a decision up to, and if I got the invoicing wrong, it was wrong in a firm's books.

That changed how I work more than any of the technology did. I write things down now. What a feature must never do, why a rule exists, what I decided against and why. I found out how much of that only lived in my head when I had to hand the whole thing to another developer at the end.

I also learned a field I had no background in by building software for it, and a year in I could argue with a lawyer about how crediting an invoice should behave. Most of that knowledge stays with the firm. What I take with me is knowing how to work this way and get something real out of it.