All work

Daftaar

Bookkeeping for trucking fleets, shipped end to end and live on both stores.

Role
Solo, end to end
Status
In production
When
2026
Stack
  • Flutter
  • NestJS
  • Prisma
  • PostgreSQL
  • Next.js
  • Shorebird
  • Docker
  • Cloudflare Tunnel
Links
Get the appdaftaar.ly

Replaces the paper ledger a fleet owner keeps. Log a trip and it settles each driver’s share, advances and payments into one running balance, then exports the month for the accountant.

Context

Small trucking businesses in Libya run on a paper ledger and a phone full of voice notes. The owner knows roughly what each driver is owed, the driver remembers differently, and the accountant gets a shoebox at the end of the month. A single-tenant Flask prototype had proven that owners would enter trips if the app settled the balances for them. Daftaar is the rebuild of that prototype as a product.

Decisions

Arabic first and right to left first, not as a translation pass. The interface, the number formatting, the PDF export and the store listing were designed in Arabic and then given an English mode, because the people who use it read Arabic and the failure mode of the other order is a product that feels imported.

The trip and balance arithmetic lives in a pure package with its own tests, shared between the backend and the mobile app, and ported line by line from the prototype that owners had already trusted. Money math is the one place a bookkeeping app cannot be approximately right, so it was isolated from every framework and covered before the first screen existed.

Multi-tenant from the first migration, with every tenant-scoped endpoint required to have a case in the tenant isolation test suite. The rule is mechanical rather than cultural: a new endpoint without an isolation test fails review by construction.

One infrastructure shape, kept boring: a Cloudflare Tunnel in front of Caddy, Docker Compose on a single box, images built in CI and pulled on deploy, a nightly database dump to object storage, and written runbooks for deploy, backup and incident. The same shape was later reused for Fin-trak so there is one topology to remember.

Shorebird for Dart-level hotfixes, so a bug in the balance screen does not wait on store review. Native changes still go through the normal release pipeline.

Consequences

The app is on the App Store and Google Play and in use by fleet owners. The shared domain package means the balance an owner sees offline on the phone and the one the accountant exports from the server cannot disagree, because they are the same code.

The cost is that the design token pipeline (W3C tokens compiled to CSS, TypeScript and Dart) and the OpenAPI-generated types are more machinery than a one-person product strictly needs. They earn their keep only because there are three front ends to keep consistent.

What I would do differently

Start the mobile app earlier. The backend and admin panel were built first against the prototype’s shape, and a few API decisions reflect what was convenient for a web admin rather than for a phone that is offline half the day.