Highlights
- Sales made offline sync exactly once, with no lost or duplicated transactions
- One TypeScript business core runs on the server, the web and inside the Flutter app
- Money and stock live in append-only ledgers enforced by Postgres itself
- Tenant isolation enforced by row-level security, tested adversarially
- Full Paystack subscription lifecycle with signed, idempotent webhooks
- Self-service custom domains for every business's public storefront
The problem
Most small businesses in Nigeria run on paper, WhatsApp and spreadsheets. The point-of-sale tools that exist either need a constant internet connection or are cash-agent terminals, and connectivity in a busy market is never constant. When the network drops, the shop still has customers at the counter.
Maldra is built for that reality: a modular business platform where the checkout (the Counter) keeps selling offline on a cheap Android phone or a desktop browser, and reconciles with the server correctly when the connection comes back.
What it does
- Counter / POS: barcode scanning with the device camera, multiple units per product (kg, litre, carton) with conversions, server-calculated tax, manager-approved discounts, held sales, refunds, cash sessions, Bluetooth thermal receipts or PDF, and PIN unlock that works offline.
- Inventory: stock adjustments with photo evidence, transfers between locations, batch and expiry tracking, cost and profit, low-stock insights, CSV import.
- Purchasing: suppliers, a purchase-order approval workflow, goods receiving and supplier balances.
- Customers & finance: customer credit balances, expenses, daily sales reports and analytics dashboards.
- Multi-branch: organisations → branches → locations, per-branch pricing, and owner / manager / cashier / inventory roles with device provisioning.
- Business websites: a public product page for each business with WhatsApp ordering and automated custom domains.
- Billing: monthly plans paid by card auto-renew, bank transfer, USSD or QR through Paystack, with a free trial.
Architecture
The codebase is a pnpm monorepo organised as ports and adapters: pure domain packages at the centre, infrastructure adapters around them, and thin apps on the outside. Dependencies only ever point inwards.
- Clients
- Counter web app (PWA)
- Owner admin
- Marketing site
- Flutter POS app
- Invoice Maker apps
- On device
- Embedded TypeScript runtime (QuickJS)
- Local SQLite / IndexedDB journal
- API
- NestJS HTTP layer
- Sync & provisioning
- Paystack webhooks
- Domain service
- Domain core
- Kernel
- Commerce
- Inventory
- Subscriptions
- Notifications
- Data & services
- PostgreSQL (RLS, ledgers, outbox)
- Object storage
- Paystack
- Vercel Domains API
- Sentry
Engineering challenges
Offline sales that sync exactly once
Every write on a device is recorded in a local journal and replayed to the server in order, by a per-device sequence number rather than the device clock, which can't be trusted. Batches are idempotent, so a retry after a dropped connection can never create a duplicate sale.
Only infrastructure failures are retried. Business conflicts, like selling stock another device already sold, are surfaced to the user, never silently overwritten. The sync path is tested against real Postgres, including several devices syncing at once and a device restarting mid-sync.
One business core on every platform
The pricing, tax, stock and sale rules are written once, in pure TypeScript. The server uses them directly, the web app uses them in the browser, and the Flutter app runs the same bundle inside an embedded JavaScript engine. Dart provides a bridge for the journal, printer, scanner, connectivity and app lifecycle.
A sale rung up offline on an Android phone follows exactly the same rules as one made on the web.
Ledger-based correctness, enforced by the database
Money and stock movements are stored in append-only ledgers; a database trigger rejects any update or delete. Balances are projections maintained by triggers, and each command commits its snapshot, ledger entries, audit entry and outbox event in a single transaction.
Tenant isolation you can't forget to apply
Every business table uses forced row-level security scoped to the current tenant, so a missing WHERE clause in application code can't leak another business's data. Isolation is tested adversarially: a raw database connection scoped to one tenant cannot see another's rows.
Real-world billing and app-store rules
The Paystack subscription lifecycle covers signed webhooks, idempotent payment references, protection against late out-of-order charges, plan upgrades and downgrades, and staff-recorded in-person payments. Mobile store builds hide every payment prompt to comply with Apple and Google Play policies.
Automated custom domains
A business can connect its own domain from the dashboard. Maldra checks the domain is registered, attaches it through the Vercel API, and a background worker re-checks DNS until it verifies, so typing someone else's domain never works.
Results
Maldra is live in production at maldra.com, with the Counter, the owner dashboard and the Invoice & Quote Maker running as separate products on the same platform. It's under active development.
Gallery


