Custom software · in production
Applications we have to live with
Situation
Three legal entities, three sets of books, and a person retyping bank statements into accounting software every month. The bank has an API. Nobody uses it, because open banking is sold to banks, not to the companies that bank there. That is how the first of these applications came about, and so did the rest — out of a problem of our own, not a brief. Nobody paid us for them, so nothing in them was built merely because it was in the spec — and nobody took delivery either, so there is no getting rid of them. That is exactly what makes them a useful reference: an application you have to use every day will tell you within a year the truth a customer never would.
What we did
Each one stands on a different problem and a different piece of technology — and we built and run all of them ourselves.
Result
Nobody retypes a statement any more: one signature covers the batch, and the month-end that used to be an evening is now a screen you glance at. The rest run the same way. None of them is a prototype we would demo and then switch off — they are things we use, and when they break, they break on us. That is the whole difference from a demo.
What is in them
-
Quvanto
Accounting for three legal entities. FastAPI over PostgreSQL, statements parsed with pdfplumber, invoices typeset to PDF with WeasyPrint and a pay-by-square QR code on them. Payments leave either as SEPA XML in the pain.001.001.03 format for upload to the bank portal, or straight through the bank payment API, where account access and payment initiation clear in a single authorisation: the whole batch from one screen with one signature.
-
OZORApp
A PWA for thirty-one people at a festival in Hungary where there is no signal: PHP with no database, state in files, and a service worker that opens the app even when the network will not. Mark the sets you want and it flags the clashes, naming what they collide with. Plus the lineup matched against what you actually listen to on Spotify — nothing is added for you, only offered.
-
Objatie
Two partners set their expectations across relationship themes independently, and the app reveals them theme by theme — only ever what they have already revealed to each other. Laravel 11 with no build step, serving two domains from one codebase, data in PostgreSQL, and the whole run works anonymously without an account. The AI comment on the result receives only axis names and a coarse band, never the raw answers.
-
Inzerátor
It sells on Bazos: you photograph the item, a model identifies it, researches the market price through a search service of our own and writes the Slovak listing, you confirm and the app posts it. The model is called through the same gateway as everything else, so the app itself holds no provider key. And since Bazos blocks the hosting provider IP, the work is done by a daemon at home that has no inbound port open at all and picks up jobs through a database notification.
-
Health Bro
A FastAPI backend on PostgreSQL, reachable only over VPN. It ingests a ring and a Garmin and joins them to what a watch cannot see: supplements, training, lab results, goals. Out of that it derives a readiness state for the day — go hard, or back off. Roughly as much test code as production code, and every warning fails the build.
What it taught us
We learned it in stages, each of them on a different layer.
OZORApp taught us that "offline-first" is not about the network being off, but about a network that lies: on the Hungarian EDGE network a call to the server neither succeeded nor failed — it simply hung, so the service worker waited forever and the app would not load at all, despite being entirely in the cache. Since then no project of ours makes a network call without its own timeout.
Inzerátor taught us to read an obstacle correctly: when a WAF blocks the hosting provider's IP, the wrong answer is to punch a hole into the home network; the right one is to reverse the direction and have a daemon listen on a database channel.
Health Bro taught us that a field name is not a contract — a field whose name promised seven days was quietly carrying fifty-nine, and the payload sent to the model had grown to a hundred and thirty kilobytes before anyone noticed.
Objatie taught us the bug need not be in the code: the deploy uploaded only part of the repository, so a registration living in a file that never shipped worked locally and returned a 500 in production.
And the accounting system taught us the most expensive one: the hard part was never the code. The bank's consent expires roughly daily while the access token lives for months — so the token keeps refreshing over a consent that is already dead, the bank returns an error that never mentions consent, and you go looking for the bug in your own code. Nothing in the documentation says this. You find it the evening before payroll taxes are due, when a batch that cleared last month suddenly does not.
At your company
How many hours a month does someone in your company spend moving numbers from one system into another by hand? We have yet to see a case where the obstacle was technical — it was always that nobody owned the job. And we are not selling you an application we already wrote: we are selling the fact that we have to maintain our own, so you know what you get, and what will break on it a year from now. The first question is always the same one, and it is not technical: which of the things a person does by hand today is even worth writing as software? Some of the time the answer is "none of it, go buy it".
What it looks like
The screenshots use sample data, not real people's accounts.
I have the official festival apps on my phone, from Pohoda and from Grape. After two days I stop opening them. This one we had open all week at Ozora — it was the only one that worked where there was no signal, and the only one that showed me where the rest of the group was heading.