utsav@homelab:~$
cd ~/projects/khatiwada-pos
KHATIWADA POS SAAS
> U1 · CPU, FROM ONE FAMILY SHOP TO A MULTI TENANT PLATFORM
utsav@homelab:~/projects/khatiwada-pos$ cat README.md
My family runs a small grocery store in Kathmandu. Sales used to live on pen and paper, no product
database, no sales history, no way to know what was actually selling. I built a browser based point
of sale for it, served from a Raspberry Pi in Sydney over a private Tailscale VPN, and it has been
in daily use at the shop since July 2026. This year I took the same codebase and rebuilt it into a
proper multi tenant SaaS product, so any small shop owner in Nepal can get their own isolated store
on the same platform.
utsav@homelab:~/projects/khatiwada-pos$ ./features --list
▸ Camera based barcode scanning, works on Chromebook and iPhone
▸ Bilingual English / Nepali cashier interface
▸ Live Bikram Sambat calendar and Kathmandu clock
▸ Weighed goods sold per kilogram or litre
▸ Password protected admin panel with CSV sales reports
▸ Isolated Docker container per SaaS customer
▸ Signed token handoff login, no shared sessions between tenants
▸ Self-service customer creation from the Master Dashboard, backed by a local provisioning agent behind a single Unix socket
▸ Fully responsive cashier screen, phone to tablet to desktop
▸ Self-serve bilingual category system with icons, a template for any shop type
▸ Per-store payment QR upload, no shop's real merchant QR baked into another shop's app
▸ Second front end for Zebra TC53 handheld scanners, same backend, same onboarding path
utsav@homelab:~/projects/khatiwada-pos$ docker inspect khatiwada-pos --format stack
RUNTIMEPython · Flask · SQLite
FRONTENDPlain HTML / CSS / JavaScript, no framework
ORIGINAL HOSTRaspberry Pi 4, Sydney, family shop only
SAAS HOSTOracle Cloud VPS, Docker per customer, Caddy reverse proxy
AUTHSigned short lived tokens handing a login off to its own container
SECURITYRate limiting, CORS allowlist, security headers, no wildcard origins
utsav@homelab:~/projects/khatiwada-pos$ git log --reverse --milestones
2026-07-02Project start. Flask and SQLite scaffold, cashier screen with scan, search and running bill, admin panel, quick tap categories, Quick Add for unknown barcodes
2026-07-03Hardened and deployed. A 54 check test suite, Dockerised with gunicorn, live behind Caddy with real HTTPS over Tailscale
2026-07-04Made it Nepali. English/Nepali toggle, live Bikram Sambat date, Nepali product names, pinned quick buttons
2026-07-08Weighed and measured goods generalised to litres
2026-07-09Full UI redesign plus automatic cache busting for shop devices
2026-07-20Commercialisation begins. Landing site and login flow scoped out to turn the single family deployment into a SaaS product
2026-07-22Login flow live. Store name plus password, signed handoff token, redirect into the customer's own container
2026-07-23Master dashboard live for day to day operator tasks: customer list, password reset, portal access
2026-07-25Forgot password flow shipped, plus real security hardening: rate limiting on auth routes, CORS allowlist, no more public .git folder
2026-07-30 to 2026-08-03Real SSH lockout incident on the VPS drove every resilience fix since: break glass console access, tested backups, and 15 minute health heartbeat monitoring across disk, memory, Caddy and all five containers
2026-07-27 to 2026-07-29Professional-tone pass: matched the customer portal's palette to the landing page, added a K POS branded login screen, removed em dashes and emoji throughout, confirm prompts on destructive actions
2026-08-18Two palette redesigns in one day, ending on a bright food-app theme (white surfaces, orange accent, real green) after live feedback; shipped a self-hosted category icon system, a modernised admin nav, and the scan button repositioned for one-handed phone use
2026-08-19Category system finished end to end: Groups renamed to Category with the old duplicate tag retired, a 21-category bilingual template built for any shop type, bulk-assign tooling for legacy products; the cashier screen given a full mobile/tablet/desktop responsive redesign
2026-08-19Admin panel mobile pass (uniform buttons, one-tap back to cashier, a themed reset control), the same category system and mobile fixes carried over to the Zebra TC53 companion app's shared admin code, and the public landing site's demo, screenshots, and copy refreshed to match the new look exactly
2026-08-20Split into dedicated SaaS template repos separate from the family shop's own app, removed the fake Starter/Growth pricing tiers, and built a real delete-customer teardown plus one-shot onboarding scripts
2026-08-20Genuine self-service customer creation shipped: a local provisioning agent on the VPS host, reachable from the dashboard container through exactly one Unix socket and never a network port, lets an operator create or delete a real customer container straight from the Master Dashboard. Proven end to end for both the browser cashier template and, separately, a Zebra handheld customer
2026-08-20Brand color discipline pass across the whole product: made orange the unmistakable brand color on both the marketing site and the POS app, fixed a mislabeled warning color, color-coded admin category tags by product type instead of an unrelated blue, and added a site-wide password show/hide toggle
2026-08-20Per-store payment QR upload replaced an image that had been hardcoded into the Docker build itself, a real bug for a multi-tenant product, alongside a scrolling header clock for small screens and a scannable barcode field in the Zebra handheld's Quick Add
ONGOINGStill the primary source of truth for the family shop plus the pilot SaaS tenants
utsav@homelab:~/projects/khatiwada-pos$