€4.51 / month 🤙 zero App Store self-hosted 💾 no AI, just maths
Case study · App Splitka

Split costs,
not friendships.

A mobile app (PWA) for splitting shared household expenses. Add a receipt in three taps — it keeps track of balances and tells you who owes whom. At the end of the period you settle up with the fewest possible transfers.

In production, in daily use since June 2026
scroll
Where the idea came from

A shared home means shared expenses — and a constant “who paid last time?”.

Revolut Groups does it sluggishly and with no analytics at all. Splitka was meant to be faster, to the point, and to work everything out by itself — no AI, no third-party cloud, on my own server. The whole idea is one loop you can go through in a few seconds:

1
Add an expensekeypad, category, who paid
→
2
Balances update themselvesgreen = to get back, red = to pay back
→
3
Settle upfewest possible transfers
What it looks like

Five screens, one loop.

Mobile-first, but on desktop it expands into a full layout with side navigation. Below are real screenshots from production.

Splitka home screen — balance, budget and what to settle
Homebalance, budget, to settle
Add expense screen — keypad and categories
Addkeypad, categories, split
Analytics screen — spending by category
Analyticstrends, categories, shops
Fixed costs screen — subscriptions and instalments
Fixed costssubscriptions, instalments, rent
Settings screen — profile and group
Settingsprofile, group, invitations
← swipe to see more →
On desktop

Same product, full layout.

The app isn’t just “a phone in the middle of the screen”. Above 1024 px it switches to side navigation, a two-column dashboard and larger type — a dedicated view, not a stretched mock-up.

splitka.ffrydrychowski.pl
Splitka on desktop — dashboard with side navigation
splitka.ffrydrychowski.pl/analytics
Splitka on desktop — analytics
Under the hood

A simple stack that doesn’t need babysitting.

The whole architectural idea: as few moving parts as possible. A static frontend, a single-binary backend, one database file — and a server for four and a half euros a month.

⚡

Frontend

SvelteKit in adapter-static mode — the whole app is just plain files, with no server behind it. It loads instantly, and you install it from the browser via “Add to Home Screen”, where it works like a native app.

SvelteKit · PWA
🗄️

Backend

PocketBase — one small Go program that gives you login, an API, real-time and an admin panel out of the box. Light and self-contained, with no stitching together of five cloud services.

PocketBase · self-hosted
💾

Database

SQLite under PocketBase. For 2–10 household members it’s more than enough, and a backup is just copying one file. Eight collections: groups, expenses, periods, settlements, fixed costs…

SQLite · 8 collections
🌐

Hosting

My own server for a few euros a month. Traffic goes through a reverse proxy with an HTTPS certificate, and the service restarts itself after every reboot. Full control, no third-party cloud.

Own VPS · HTTPS
Client
PWA
static build served as plain files
→
Entry layer
Reverse proxy
HTTPS certificate and routing traffic to the right service
→
API + Auth
PocketBase
REST, real-time and admin panel · data in SQLite
Why this way

Four decisions that shaped the project.

PlatformPWA, not native

No App Store, no reviews, no waiting for approval. You send a link, tap “Add to Home Screen” — done. Updates arrive automatically the next time you open it.

BackendPocketBase, not Firebase

Self-hosted, so the data lives on my server, not with Google. Auth, API and real-time all included — no stitching together of five cloud services.

IntelligenceZero LLM

Settling debts is pure maths, not a job for a model. Speed and predictability matter more here than trendy gimmicks — the app calculates instantly and always the same way.

DatabaseSQLite

The simplest tool, and more than enough for a few people. No separate database server, no configuration, backup in a single file.

Interesting moments

Three problems that had to be cracked.

Algorithm

Fewest possible transfers

Instead of “everyone pays everyone”, the app calculates the smallest set of transfers that evens out balances: it takes the biggest creditor and the biggest debtor, pairs them in one transfer, and repeats. A simple greedy approach — four people settle up in 2–3 transfers instead of six.

Bug

The date that went back a day

new Date(...).toISOString() converted local midnight to UTC — and in Poland (UTC+2) that’s 10 p.m. the previous day, so the expense landed a day early. Fix: building the date as a plain string YYYY-MM-DD, with no time-zone conversion at all.

Privacy

Private expenses that must not leak

At first, the dashboard and analytics loaded all of the group’s expenses — including other people’s private ones, which became visible and were counted in the wrong balances. Fix: filtering at the query level, so other people’s private entries never leave the server.

~4,51 €
per month for all hosting
< 3
taps to add an expense
8
collections in the database
50–100 MB
RAM on the backend
June 2026
in production, in daily use