The parts that are hard, and how they get solved.
Six capabilities, one worked example, and the practices that keep a portfolio this size from collapsing into maintenance.
- Capabilities
- 6
- Primary stack
- TypeScript end to end
- Data
- PostgreSQL · Prisma · SQLite
- Targets
- Web · PWA · Desktop
What the practice covers
Offline-first architecture
Local SQLite as the source of truth, append-only sales, client-generated UUIDs, idempotent replay and deterministic conflict rules. Cash registers do not get to stop when the network does.
Multi-tenant data modelling
Tenant and warehouse scoping enforced at the query layer, not the UI: 76 Prisma models, row-level filtering, per-location pricing, stock and credit limits.
Product surfaces at scale
Design systems that survive 60+ screens — dual-screen POS, dense data tables, keyboard-first flows, 32 themes, skeleton states and tours, all in one codebase.
Desktop + web from one codebase
The same application ships as SSR web, installable PWA and a Tauri desktop binary for macOS, Windows and Linux, with platform utilities abstracting the differences.
On-device intelligence
Natural-language querying over business data using a browser-resident model in a web worker — no per-query API cost, no data leaving the device.
Measurement as a product
Heatmap rendering, element-level revenue attribution, funnel diagnostics and page-quality grading — turning raw interaction data into decisions.
A sale that cannot be lost.
This is the shape of the algorithm behind TallyhubGH's point of sale, and the reason the same pattern appears in Farm Ops and MamaCare. Four properties do the work:
- The client owns the id. A server-assigned key means the client cannot tell a retry from a new record. A client UUID makes every write idempotent for free.
- Local first, unconditionally. The sale is committed to device storage before anything is attempted over the network, so the receipt prints either way.
- Append-only history. Nothing is edited in place. Voids and refunds are new entries, which is what makes an audit possible at all.
- Deterministic reconciliation. Conflicts resolve by documented rules, never by whichever request happened to arrive second.
The cost is real: two sources of truth to keep honest, and a reconciliation path that has to be tested as carefully as the happy path. The benefit is that a power cut is an inconvenience rather than a lost day of trading.
// The rule that makes an offline till safe: the device writes first,
// the server converges later, and every write can be replayed.
type SaleStatus = 'pending' | 'synced' | 'failed';
async function completeSale(cart: Cart, device: DeviceId): Promise<Sale> {
const sale: Sale = {
id: uuid(), // client-generated, never server-assigned
receiptNo: nextLocalReceipt(),
lines: cart.lines,
total: cart.total,
createdAt: Date.now(),
device,
status: 'pending',
};
await local.sales.insert(sale); // append-only; the sale exists now
queue.enqueue({ kind: 'sale.create', id: sale.id });
return sale; // the receipt prints regardless of network
}
async function drain(): Promise<void> {
for (const job of queue.pending()) {
try {
// Idempotency-Key = the sale id, so a retry can never double-post.
await api.post('/sales', await local.sales.get(job.id), {
headers: { 'Idempotency-Key': job.id },
});
await local.sales.mark(job.id, 'synced');
queue.ack(job);
} catch (error) {
if (isConflict(error)) {
await reconcile(job.id); // deterministic rules, never last-write-wins
queue.ack(job);
continue;
}
queue.backoff(job); // exponential, capped; order preserved
}
}
}Condensed from the offline sync algorithm documented in the TallyhubGH repository.
The stack, honestly
Chosen for reach and longevity rather than novelty — one language across client, server and scripts, and a database that can be reasoned about.
Interface
- Vue 3
- Nuxt 3
- Astro
- React
- TypeScript
- Tailwind CSS
- DaisyUI
- GSAP
- Motion
- ApexCharts
Runtime & services
- Node.js
- Nitro
- Express
- WebSockets
- Service workers
- Web workers
- REST
- Server-sent events
Data
- PostgreSQL
- Prisma
- SQLite
- Redis
- S3-compatible storage
- Migrations
- Seeding pipelines
Platform
- Tauri
- Docker
- Cloudflare
- Render
- GitHub Actions
- PWA
- Playwright
Security
- WebAuthn / passkeys
- JWT sessions
- bcrypt
- Role-based access
- Manager PIN gates
- Impersonation audit trails
Intelligence
- WebLLM
- On-device inference
- Natural-language querying
- Anomaly surfacing
- Forecast summaries
Practices that survive contact with deadlines
Documents live with the code
Sync algorithms, data-flow diagrams and implementation plans sit in the repository beside what they describe. A design that only exists in someone’s head is a design that will be reimplemented incorrectly.
Invariants over tests alone
Money paths get properties that must always hold — a sale is append-only, a reversal is a new entry, a receipt number is never reused — expressed in the schema where possible, in checks where not.
Skeletons for every dense view
An operational table that reflows twice while loading reads as broken. Loading states are designed at the same time as the view, not bolted on when someone complains.
Platform differences behind one door
Feature code never asks whether it is running in a browser, a service worker or a Tauri window. A utilities layer answers that question once.
Reduced motion is a real mode
Every animation in this portfolio — including the canvas work on the home page — has a still equivalent that ships when the visitor asks for it.
Measure before optimizing
Field instrumentation over lab scores, real interaction data over intuition. If a change cannot be measured, it is a preference rather than an improvement.