Retail SaaS
Jul – Sep 2026
Independent product
Mero Pasal
Multi-tenant retail SaaS for Nepali shops — isolated per shop at the database level, with a storefront attached.

Stack
- Django
- DRF
- PostgreSQL RLS
- React
- Vite
- TypeScript
- Celery
- Redis
- Docker Compose
- Caddy
- Tailwind CSS
- Playwright
- Vitest
- Pytest
Evidence
- Merged pull requests
- 113
- Commits
- 493
The problem
What this had to solve.
Small Nepali retailers run on a paper khata for customer credit and a calculator for VAT. Off-the-shelf POS software assumes a Gregorian fiscal year, English-only staff and one shop per install. The platform had to give every shop its own subdomain and its own strictly isolated data, work on a cheap phone behind the counter, and produce a VAT register the tax office will accept.
Architecture
How it actually works.
Both shops travel the same code path. Middleware resolves the subdomain and sets a session variable; PostgreSQL row-level security scopes every row from there. A query that forgets its tenant filter returns nothing rather than another shop's data.
What I built
My contribution.
- 01
Developed a multi-tenant retail SaaS with isolated shop subdomains, branch-aware staff permissions, bilingual UI, Bikram Sambat reporting and IRD-oriented billing.
- 02
Built mobile-first sales, catalog, inventory, purchasing, customer credit (khata), expense, payment, reporting, VAT-register and day-close workflows.
- 03
Added an online storefront with tenant-controlled merchandising, website pricing, offers, templates, OTP customer login, checkout, idempotent ordering and order tracking.
- 04
Implemented account security, device-session revocation, audit logging, tenant-aware rate limits, privacy-safe observability, typed OpenAPI contracts and permission-safe exports.
- 05
Created a platform-admin control plane for tenant provisioning, plans, subscriptions, feature flags, usage metering and audited support sessions.
The hard part
Tenant isolation that survives my own mistakes
Filtering every queryset by tenant works right up until one developer forgets one filter — and then shop A is reading shop B’s sales. I did not want the guarantee to depend on discipline, so isolation moved into PostgreSQL row-level security: middleware resolves the subdomain, sets a session variable, and RLS policies scope every row automatically. An accidental unfiltered query returns nothing instead of returning a competitor’s revenue. The genuinely tricky part was the escape hatches — background jobs, the platform-admin control plane and support sessions all legitimately cross tenants, so each needed an explicit, audited elevation path rather than a bypass someone could reach for casually.
Read the full note, with the code →Interface
What it looks like in use.

Udharo (khata) as a real ledger: each credit bill and part-payment by cash, QR or eSewa rolls into a running balance.

Each shop gets its own storefront on its own host, selling from the same catalog as the counter.

A phone-first counter sale: staff can bargain only inside the owner’s price range, then settle with cash or QR.