BillTick — Local-First Billing for Small Businesses
A zero-backend invoice and receipt generator with built-in time tracking — designed for freelancers and small businesses that want professional billing without surrendering their data to a third-party server. Everything runs in the browser; nothing leaves the device.
Billing tools come with strings attached
Most invoicing tools assume the same trade: you hand over your client list, line items, and billing history in exchange for the convenience of a web app. For freelancers and small operators, that’s a high-friction deal — accounts, subscriptions, cloud sync, and the ambient risk of vendor lock-in for something as simple as “send a PDF invoice”.
BillTick was built around a different premise: the user’s billing data should live on the user’s device. No account creation, no analytics, no server roundtrip. Invoices, receipts, and time entries are stored locally in the browser and exported as PDFs on demand.
No telemetry means catch it before ship
Testing is my primary discipline, and on a privacy-by-design product with no analytics coming back from production, that discipline has to be unusually tight: there is no signal to flag a regression after release, so every meaningful failure has to be caught before deployment. Vitest + Testing Library cover the persistence layer (Dexie round-trips, IndexedDB schema migrations) and the pure-function math behind totals, taxes, and time durations — small surfaces with high blast radius if they silently drift. React Hook Form + Zod schemas double as runtime test cases at the input boundary, rejecting invalid state before it ever reaches storage.
The highest-ROI surface is the PDF export path: every supported browser engine renders
@react-pdf/renderer output slightly differently, so a fixed reference invoice
gets rendered in each engine and diffed against a known-good baseline. In a team setting,
that work is the right thing to delegate to a junior tester with a snapshot harness —
repeatable, structured, and exactly the kind of regression hunting that benefits from a
fresh pair of eyes — while I keep the data layer, the math, and the licensing flow that
gates the paid tier.
Why local-first, and what it cost
The most consequential decision was eliminating the application backend entirely. A traditional SaaS architecture would have made billing data trivially syncable across devices, but it would also have meant standing up auth, storage, and the operational overhead of running a service for users who explicitly didn’t want a service running on their behalf. IndexedDB — accessed through Dexie — was the right primitive: durable, asynchronous, and large enough to hold years of invoice history without pressure.
PDF generation runs entirely in the browser via @react-pdf/renderer, which
keeps the local-first contract intact — no document ever touches a remote server to be
rendered. Browser rendering engines disagree on margins, font fallbacks, and page-break
behaviour, so the export path had to be explicitly verified rather than assumed; each
engine was checked against a known-good invoice layout before the feature was considered
shipped.
State management is deliberately small: Zustand for in-memory app state, Dexie for persistence, Zod plus React Hook Form for input validation. No global context, no Redux ceremony, no server-state library — because there is no server state to manage.
What the platform does
Invoice & Receipt Builder
Compose invoices and receipts with line items, taxes, and configurable payment terms.
Built-in Time Tracking
Stopwatch sessions or manual time entries — billable hours feed straight into invoices.
Cross-Browser PDF Export
Generate clean, print-ready PDFs directly in the browser — validated across major engines.
Local-First Persistence
All data lives in IndexedDB on the user’s device — no servers, no accounts, no analytics.
Client & Project Management
Organise recurring clients and projects with reusable profiles for faster billing cycles.
Backup & Restore
Manual JSON export and import — portable backups the user owns and controls outright.
See it in action
Product views
How it’s built
A modern client-side stack with no application server — only static hosting on Vercel’s edge, and a thin API surface for license activation and Stripe webhooks.
What I worked around
No QA handoff, no backend to lean on, and no analytics to observe usage after release — the privacy posture had to hold all the way through. That meant every bug had to be caught before deployment, since there was no telemetry coming back to flag a regression. The offline-first contract also forced careful state handling: persistence, conflict resolution, and PDF generation all had to work without a network round trip available as a fallback.
How I built it
BillTick is a solo build — I scoped the product, designed the architecture, wrote the front-end, validated the PDF export path across browsers, and shipped to Vercel without a QA handoff. As co-founder I also own the product framing: who it’s for, what it deliberately doesn’t do, and how the local-first contract is communicated to users.
Sole engineer & co-founder. Scoped, designed, coded, tested, and shipped — zero-backend architecture, cross-browser PDF accuracy validated end-to-end, deployed live to Vercel with no QA team in the loop.
What I’d do differently
I’d invest earlier in an automated visual-regression layer for the PDF output. Browser-engine differences in PDF rendering are easy to miss by eye and stable enough between releases that a scripted snapshot diff would catch drift far more reliably than manual cross-browser passes.