The problem
A sole trader finishes a job at five o’clock and has a choice: write the invoice now, on a phone, standing in a driveway or do the paperwork at nine at night after dinner. Most of them do it at nine at night, and some of them do not do it at all for a fortnight, which is a fortnight they are not being paid for work they have already done.
The software that exists for them is mostly built for larger operations. It is priced per seat, so hiring an apprentice puts the price up. It caps how many jobs you can do in a month. And a good deal of it stops working the moment the signal does which is exactly where trade work happens: basements, plant rooms, lift shafts, a shed forty minutes past the last tower.
We wanted to find out whether a small, careful product could serve that market properly. So we built one.
What we built
The application. Quotes, invoices, jobs, clients and crew, designed phone-first because that is where it gets used. Documents are issued with sequential numbering that has no gaps, because that is what tax authorities require and it is the rule most software quietly breaks. Money is handled as integers throughout. No floating-point value ever touches a price.
The marketing site. Fifteen pages, built as a custom WordPress theme with no page builder and no plugin stack: home, features, pricing, a guided tour of the real app on three device sizes, a competitor comparison with cited sources, a booking form, and a page per country. Everything degrades gracefully without JavaScript.
Subscription billing, an error-tracking system, and a privacy policy and terms of service written to match how the software actually behaves rather than copied from a template.
Decisions that shaped it
It has to work with no signal
Offline is not a feature bolted on at the end; it decides the architecture. Work done on a phone is written to a local queue first and sent when the connection returns, so a quote written in a basement survives the trip back to the van.
Logging out deliberately does not clear that queue. Unsent work belongs to that phone, and wiping it because somebody signed out would destroy the exact thing the queue exists to protect.
The tax has to be right in four countries
This is the unglamorous part that decides whether the product is usable at all. Australian GST at 10% with the ABN and the words “Tax invoice” on every document. New Zealand GST at 15% with what IRD expects. US sales tax, which differs by state and often by county, so the rates are the customer’s to set. Canada’s GST and HST, 5% federally, 13% in Ontario, 14% in Nova Scotia, 15% in New Brunswick, Newfoundland and PEI.
Two provinces on one invoice is normal for a Canadian contractor, so two tax rates have to sit on one document and stay separable for the return. Every document stores the rate it was drafted with, so a rate change in a budget speech never rewrites history.
Getting paid the way your country pays
Most invoicing software offers a card payment button and a box to type your bank details into. That is the wrong answer in three of our four markets.
A Canadian small business gets paid by Interac e-Transfer to an email address. An Australian gets paid by PayID, in seconds, for nothing. An American, increasingly, by Zelle. So the product offers each country the methods that country actually uses, in the order that gets the money there fastest — and puts each value on the invoice as its own line with a copy button, rather than as a paragraph the customer has to pick apart and retype into a banking app.
The account numbers are checked as they are entered. A US routing number is validated against its own checksum; an Australian BSB is normalised to the way banks write it. A transposed digit in an account number is not a form error. It is money arriving in a stranger’s account, and no bank will get it back.
Billing that does not require a foreign company
The product is operated from the Philippines, and Stripe does not open accounts for sellers there. Rather than treat that as a blocker, we used it: billing runs through Paddle as merchant of record, which means the payment provider registers for and remits sales tax in every market the product sells into.
It costs more per transaction than a payment gateway. It removes the need to register for tax in four countries, and it was the right commercial trade for a business at this stage. Choosing it was a business decision before it was a technical one.
Security enforced by the database, not by the code
Each business’s data is isolated by PostgreSQL row-level security, keyed to the account making the request. The boundary is a database grant — so a bug in application code cannot leak one customer’s clients to another, because the application role is not permitted to read them in the first place.
The operator’s own admin console is a separate deployment with its own database credentials, and support access is read-only. There is no way to sign in as a customer.
Everything works without JavaScript
Every form posts and works on the first paint. The currency switcher, the device tabs, the copy buttons, all of it enhances a page that already functions. The people using this are on old phones with bad connections, and a screen that needs a hydrated bundle before it does anything is a screen that does nothing when it matters.
Keeping it honest
Two habits did more for quality than anything else on this project.
Testing the things that fail quietly. 331 automated tests, weighted towards the places where being nearly right is the same as being wrong: tax arithmetic across thousands of generated amounts, Russian plural forms, webhook signature verification, permission boundaries, and what happens to an account when a card fails. A further 22 checks run against the marketing site in a real browser and verify behaviour that prices change when you switch currency, that the choice survives a page load, that every image has alternative text, that the structured data parses.
Auditing the marketing against the software. Late in the build we checked every claim on the site against the code and found two features being advertised that had never been built. They came out the same day. Nothing on a Pordiya page describes something the product does not do — which sounds like a low bar, and in this industry is not.
By the numbers
- 331 automated tests
- 22 behavioural checks on the marketing site, run in a real browser
- 4 countries, each with its own tax rules, currency and payment methods
- 3 languages, including correct Russian plurals
- 15 pages of marketing site, hand-built with no page builder
- 0 floating-point numbers anywhere near a price
Where it is now
Pordiya is built, tested and ready to launch. It is our own product rather than a client engagement which is why we can talk about the decisions inside it in this much detail.
It is also the clearest answer we can give to a question we get asked a lot: can you build the whole thing? Product design, multi-tenant architecture, offline sync, multi-currency billing, tax compliance, a marketing site, the legal documents underneath it, and the deployment runbook that ships it.
Yes. This is what that looks like.
Great to have worked with a team that knows what they are doing.