Ottr Omni-Ledger — branch-based commerce platform
E-commerce, retail POS, restaurant POS and mobile from one codebase, on an append-only inventory ledger with seven payment providers.

Background
A single platform for a business that sells through a web store, a shop counter and a restaurant floor at the same time. One organisation, many branches and warehouses, one stock truth. It ships as a multi-org admin, a storefront, an Electron POS for retail, a restaurant POS with QR-scan customer ordering, Flutter apps for customers and waiters, and an AI marketing studio.
I built all of it, from the Prisma schema to the thermal-receipt printing. It is the largest system I have built.
Screens


The problem
Nepali SMBs run e-commerce, retail and restaurant from separate tools that disagree about stock, and pay through local gateways that no global platform supports. Stock in particular has to survive concurrent sales from a website, a counter and a kitchen, offline POS terminals that sync later, and the audit questions that follow.
The second constraint was deployment. One client might want only the storefront, another only POS. The system had to run as a subset without forks.
Approach
- Make inventory an append-only ledger. Every movement is a row: RECEIVE, SALE, TRANSFER_IN and TRANSFER_OUT, ADJUSTMENT with a mandatory reason, RESERVE and RELEASE that move on-hand to reserved with no net change, and WASTAGE. Quantities are Decimal(12,4) so kilograms and metres work. Levels are derived, never edited.
- Put payments in a Go gRPC service with a provider interface: Stripe, eSewa, Khalti, Fonepay and ConnectIPS, PayPal, Razorpay and manual. Config is per organisation. The POS handles cash with change, QR payments with two-second polling and auto-confirm, card terminal and split tender.
- Multi-tenancy as Organisation, Member, Branch and Warehouse, with Super Admin, Org Admin and Shop Admin roles, and per-org subdomains for store, admin and POS.
- Split the API into three NestJS entry points (admin, e-commerce, POS) on one schema, with Go services for inventory, payments and MeiliSearch-backed search, and RabbitMQ and BullMQ between them.
- Offline-first POS on Electron: SQLite product cache, an order queue that syncs when the network returns, USB HID barcode scanning, silent 80 mm thermal printing, two-step login with branch selection.
- Docker Compose profiles (dev-full, dev-ecommerce, dev-pos, dev-admin) and live module control in the admin panel so a deployment runs only what the client bought.
- AI on the edges: a Rust chatbot service per storefront (works with Ollama) and a marketing studio for campaigns, audiences, brand kit, copy, image and video, calendar, coupons, affiliates and approvals.
- Operations as a first-class module: Prometheus, Grafana, Loki, Promtail and blackbox exporter; Caddy edge with nginx; Swagger per API; Playwright end to end; commitlint.
Architecture
Outcome
- Storefront, admin and edge deployed under ottr.com.np subdomains with staging and production compose files, and an ops deployment log.
- Still active: the last commit is from the day this site was built.
- The ledger, payment and tenancy patterns were reused in Ottr Kiln and GC LAL.
Lessons
- An append-only ledger costs nothing extra to write and answers every 'why is stock wrong' question later. Derived levels with a daily stat table keep reads fast.
- Reserve and release as explicit movements, not a flag, is what made online checkout and counter sales coexist.
- Five languages in one monorepo is defensible only with go.work, Turborepo and protobuf contracts. Without those it would have collapsed.