Logo Lanfrica

Alphaguyasa/Suq

Domain:

digital infrastructure

Record type:

software
Creator:
Alp
Host:
Offline-first point-of-sale and inventory PWA for Ethiopian shops. Next.js 15, Dexie, Supabase, Serwist. # ሱቅ / Suq — Offline-First POS & Inventory A point-of-sale and stock system for small shops that **keeps working when the internet and the power go out**, then reconciles cleanly when they come back. Built for Ethiopian retail: Amharic-first UI, ETB pricing, 80mm thermal receipts, runs on a cheap Android tablet behind the counter. --- ## The one architectural idea that matters Everything else here is ordinary CRUD. This is not: > **Never sync stock quantities. Sync stock *movements*.** If two tablets are offline and both sell the last case of water, and each syncs `stock_qty = 11`, one shop's sale silently vanishes. Last-write-wins destroys data. If instead each device appends `{product, qty_delta: -1}` and stock on hand is `SUM(qty_delta)`, both sales survive and the arithmetic is correct no matter what order they arrive in. Append-only rows commute; absolute values don't. The same principle covers sales — immutable and append-only, where a mistake becomes a `void` row rather than a deletion — and gives you an audit trail as a free side effect. `docs/BUILD_GUIDE.md` develops this properly. --- ## Stack | Layer | Choice | |---|---| | Framework | Next.js 15 (App Router) + TypeScript strict | | Styling | Tailwind CSS v4 | | Local database | Dexie 4 (IndexedDB) — **the source of truth** | | Cloud database | Supabase Postgres — a replica, never authoritative | | Offline shell | Serwist (`@serwist/next`) | | Barcode | USB scanner (acts as a keyboard) | | Receipts | CSS `@page` at 80mm | | Deploy | Vercel | **Runtime cost: zero.** No per-transaction API, no metered services. A CRUD app with a careful sync layer. --- ## Quick start **Prerequisites:** Node 20+, a Supabase project (free tier is fine). ```bash git clone github.com cd Suq npm install ``` Create `.env.local` from the example: ```bash cp .env.example .env.local ``` Fill in the two values from your Supabase project (Settings → API): ``` NEXT_PUBLIC_SUPABASE_URL=ht …

Languages