All projects

Offline-first app2026

Tchona

A phone app that shows a small trader their real turnover, margins and month-end forecast from the prices and sales they enter, and works with no internet.

Solo — product, design, development and deployment

The Tchona dashboard on a phone: 'Bonjour Awa', today's turnover 1 075 F with 'Ce mois : 8 725 F' below, 'Vente' and 'Depense' buttons, a 'Benefice du mois' card showing -10 886 F in red, a 'Top produits' list (Savon, Bissap, Sachet d'eau pure), and a 'Depenses du mois' card at 19 000 F with Loyer as the top item.
The Tchona dashboard on a phone: 'Bonjour Awa', today's turnover 1 075 F with 'Ce mois : 8 725 F' below, 'Vente' and 'Depense' buttons, a 'Benefice du mois' card showing -10 886 F in red, a 'Top produits' list (Savon, Bissap, Sachet d'eau pure), and a 'Depenses du mois' card at 19 000 F with Loyer as the top item.

Tchona ("look" in Kabiye, the language of my ethnic group in Togo) is an offline-first phone app for small traders: market sellers, shopkeepers, street vendors, wholesalers and food makers. It turns everyday entries (products, sales, expenses, credit given to clients) into figures a vendor rarely gets to see: turnover by day, week and month, margin per product, a month-end projection, and the point where sales stop covering fixed costs. A "what if" simulator lets them test a price change or a different sales pace before committing to it. Everything runs on the phone with no account and no network; data is backed up as an encrypted file shared over WhatsApp. It started as a personal project to help one market vendor and is now used by two.

The problem

A vendor sets a price on each item but never gets to a clear picture of what those prices produce. Over a day or a month, what is the actual turnover? Which products carry the margin? Would raising one price, or selling a bit more each day, change anything? Without doing the arithmetic by hand there is no answer, so pricing and stock decisions are made on feel.

The approach

I modelled the vendor's day as a few simple objects (products with a computed cost of goods, sales, expenses, client credit) and built every figure on top of them, on the device: turnover by period, margin per product, a weighted moving average forecast, days before a product runs out. The interface asks one question per screen in plain language, with large buttons and a number pad, so recording a sale takes a few taps. The app is a Vue 3 PWA with Dexie (IndexedDB) as the source of truth; it installs from a WhatsApp link, works fully offline, and backs up to an encrypted file the vendor sends to themselves or a trusted contact.

The result

  • A vendor now sees turnover by day, week and month, margin per product and a month-end projection, without doing any calculation.
  • The simulator answers the recurring question, "what if I change this price or sell more," with a concrete profit figure before the decision is made.
  • Two vendors use it day to day, mainly for the projections.
  • Runs fully offline and installs from a WhatsApp link; in production at tchona.vercel.app.

Key features

  • Quick sale entry: one question per screen (product, quantity, price, paid or on credit), a few taps to record.
  • Automatic cost of goods and margin: enter what you paid, the app computes unit cost, margin and a suggested selling price.
  • Turnover and profit by day, week and month, with top products and a list of unpaid client credit by name.
  • Forecasts: month-end turnover from a weighted moving average, and days before each product runs out of stock.
  • "What if" simulator: test a price change, a daily sales pace or an expense change and read the projected profit against the current one.
  • Stock tracking with a low-stock alert threshold per product; expenses, recurring expenses and monthly budget caps per category.
  • Commissions for people who pay a cut on sales: percentage, fixed, per unit, tiered or mixed, on total turnover, one product or profit.
  • Works offline; encrypted file backup shared over WhatsApp or to a trusted contact; optional PIN lock.
Engineering — Architecture, decisions and trade-offs

Architecture

Tchona is a Vue 3 single-page app rendered inside a phone-width shell, with Dexie (IndexedDB) as the source of truth and no server involved in normal use. Business logic sits behind a repository layer (src/data/): eleven entity contracts (CRUD plus named domain operations), a local Dexie implementation, a shared contract test suite that any implementation must pass, and a factory the rest of the code calls instead of touching Dexie. On top of the repositories, a services layer computes everything the vendor sees: dashboard aggregation, a weighted moving average forecast (last 7 days weighted x3, 8 to 14 days x2, 15 to 30 days x1), stockout prediction, an eight-case commission engine, and transformation recipes with cost scaling. Pinia holds view state, Vue Router guards the flow (onboarding, then optional PIN). The app is an installable PWA via Workbox with an offline navigation fallback, plus an automatic local backup written to OPFS every few minutes and on backgrounding; manual backups are an AES-GCM encrypted .tchona file (PBKDF2, 600k iterations) shared through the native share sheet. A second storage path is built and documented but disabled by a feature flag: Supabase (Postgres, Auth, Row Level Security) with a hand-rolled "outbox" sync protocol (an append-only op_log table, push_operations / pull_operations RPCs, UUID idempotency, last-write-wins per row), migrations versioned in SQL. Tests run on fake-indexeddb (~487 cases across 51 files) and GitHub Actions runs type-check, tests and build on every push; deployment is Vercel.

Engineering challenges

  • Every figure computed on the phone with no backend: dashboard aggregation, the weighted moving average forecast and stockout prediction all run against Dexie in the browser, fetching each date window once rather than per product.
  • Keeping data safe on a single phone with no account: an automatic local backup to OPFS every few minutes, plus an encrypted .tchona file the vendor shares over WhatsApp or to a trusted contact, with a weekly reminder.
  • Making a future backend possible without a rewrite: business logic was moved behind a repository interface with one shared contract test suite, service by service over about ten pull requests, and the Dexie ids were migrated from auto-increment to UUID.
  • One commission engine for eight type and target combinations (percentage, fixed, per unit, tiered, mixed, over total turnover, one product or profit) that gives the same result for a real period and for the simulator's per-product what-if.

Technical decisions

  • Dexie/IndexedDB as the source of truth rather than a hosted database: the app had to work with no network and no account from the first launch, on a phone that may spend the day on a market stall.
  • A hand-rolled "outbox" sync protocol over PowerSync, ElectricSQL or RxDB: the "one account, one vendor" rule removes multi-writer conflict resolution, so an operation log with cursor-based pull and UUID idempotency is enough and sits on top of Dexie unchanged. Six alternatives were compared and rejected in writing (ADR 0001).
  • Distributed as a PWA installed from a WhatsApp link, not an app store: no store account, no review delay, updates land immediately.
  • No UI transitions: added, then reverted, because instant screens read better for a tool used quickly at the counter.

Stack

  • Vue 3
  • TypeScript
  • Vite
  • Pinia
  • Vue Router
  • Dexie (IndexedDB)
  • Tailwind CSS 4
  • vite-plugin-pwa / Workbox
  • Web Crypto (AES-GCM, PBKDF2)
  • Supabase (Postgres, Auth, RLS)
  • Vitest
  • GitHub Actions
  • Vercel

Solo — product, design, development and deployment — Personal project, started to help a market vendor; now used by two vendors (2026)

Next projectCommunity Platform