💡 About the Application
OneBill is a multi-tenant billing & inventory SaaS built for small retail shops, kirana stores, boutiques, and similar businesses. It gives every shop owner an end-to-end back-office — from product catalog and barcode scanning to checkout, inventory, expenses, multi-store reporting — wrapped in a role-based app with a Super Admin → Admin → Owner → Worker hierarchy.
🎯 What Owners Get
- A POS / checkout system that prints 58mm or 80mm thermal receipts.
- Catalog & inventory with GST, HSN, multi-store stock, and batch/expiry tracking.
- Customer ledger with loyalty points and reminders.
- Expenses, bank accounts, suppliers, and staff with attendance.
- Reports for sales, P&L, inventory, staff performance, and stores comparison.
- Multi-worker support with per-worker module grants.
- Subscription-gated modules so customers pay only for what they use.
🏗️ Who Uses It
- Super Admin — owner of the platform (manages admins & platform settings).
- Admin — onboarding operator who creates owner tenants & manages their plans.
- Owner — the shopkeeper / tenant running the business.
- Worker — cashier / staff at the shop counter.
- Public — visitors for registration, login, password reset.
🛠️ Design Goals
- Modular by design — every feature is a module that can be toggled per tenant.
- Multi-tenant safe — strict
owner_idscoping across every query. - Secure by default — JWT with server-side session revocation, bcrypt, Fernet at rest, CSRF, CSP, rate limiting.
- Fast at the counter — barcode scanning, atomic stock reservation, instant checkout.
- Operable — Docker-ready, async Motor, audit logs, admin activity logs.
📌 User Types at a Glance
| # | Role | One-Line Purpose |
|---|---|---|
| 1 | Super Admin | Platform owner — manages admins, transfers owners, controls platform policies. Has every module. |
| 2 | Admin | Reseller/operator — creates owners, manages their module access, subscriptions and alerts. |
| 3 | Owner | Shop/business tenant — runs the shop with a full back-office (sales, inventory, reports…). |
| 4 | Worker | Cashier/salesperson — uses a subset of the owner's modules; can never exceed owner grants. |
| 5 | Public / Guest | Visitor — can register, log in, or reset password only. |
👑 Super Admin Features
Platform-level superuser
🔐 Authentication & Account
- Log in to the platform with bootstrap credentials.
- Forced first-run change-password flow.
- Manage personal profile, sessions, and password.
👥 Admin Management
🗺️ Tracking & Oversight
- Track Map — visual hierarchy: Super Admins → Admins → Owners → Workers.
- View all admins, all owners (with assigned admin), and all workers (with assigned owner).
- Owner / admin relationship graph for accountability.
⚙️ Platform Settings
- Default modules enabled for new owners.
- Platform branding / configuration.
- Global toggles and defaults (
/super-admin/settings).
🧩 Admin Module Grants
- Grant / revoke admin-only modules to plain admins.
owner_stats— detailed statistics drawer.alerts— send and manage alerts to owners.- Plain admins only see owners they have been granted access to.
🔒 Permissions
- All system modules (auth, profile, subscription, sessions, dashboard).
- All business modules (full business bypass).
- All admin modules.
🛠️ Admin Features
Created by a Super Admin
🧑💼 Owner (Tenant) Onboarding
must_change_password flag on first login.🧩 Manage Owner Module Access
- Enable / disable modules for any owner they manage.
- Toggle business modules: products, inventory, sales, customers, expenses, bank, reports, stores, suppliers, staff, alerts, batches.
- Audit log of all grant changes.
📊 Owner Statistics
- Detailed owner stats per owner.
- Sales totals, expenses, profit.
- Product count, customer count, worker count.
- Active sessions and subscription status.
🔔 Alerts Management
- Send alerts/notifications to their owners (requires
alertsmodule). - Configure alert rules and view history.
- Stock and business alerts dispatched via SMTP / WhatsApp.
💳 Subscription Management
- Grant subscription to an owner (plan, start, end date).
- Renew subscription for an owner.
- View subscription status:
active·expired·grace. - Invoices, plan tier, expiry date, grace window.
📜 Activity & Tracking
- Personal admin activity log.
- View list of owners they created and manage.
- View track map (admins → owners → workers).
🔒 Permissions (Default)
- All system modules + all business modules (business bypass).
- Does not automatically have admin modules — must be granted by Super Admin.
🏪 Owner Features
The primary tenant
module_grants. Has PrintSettings, Subscription, and full back-office access.🖨️ Print Settings (58mm / 80mm)
- Header note, footer note, thank-you message on receipt.
- Paper size: 58mm or 80mm.
- Settings inherited by all workers (used at receipt printing).
🛡️ Security & Recovery
- Forced change-password-required flow on first login.
- Password reset via tokenized email link.
- Active session monitoring and revocation.
🔒 Permissions
- All system modules (always): auth, profile, subscription, sessions, dashboard.
- Business modules per
module_grants(default =LAUNCH_CATALOG_KEYSfor fresh accounts).
🧑💻 Worker Features
Created by an Owner
effective = worker.grants ∩ owner.grants🚫 What Workers Cannot Access
/inventory · /barcodes · /stores · /bank · /staff ·
/reports · /workers/modules · /admin/* · /super-admin/*.
Any module not granted to them shows a friendly Module not available page.
🌐 Public / Guest Features
Unauthenticated users
🔐 Authentication
🛡️ Security Layers Seen by Guest
- Login rate limiting (slowapi per-IP).
- Account lockout after failed attempts.
- CSRF protection (double-submit cookie pattern).
- CSP enforced; security headers applied.
🔒 Cross-Cutting System Features
These run across the platform regardless of role.
owner_id; strict isolation.jsbarcode) + scan (@zxing/browser) + 58/80mm templates.deploy.md guide.⚡ Database Operations / sec (Estimated)
Realistic per-shop baseline estimates for a single tenant operating at moderate retail throughput (one busy checkout counter). Values represent peak ops/sec against MongoDB (Motor async driver). Reads are separate from writes; totals include both.
📊 Per-Module Throughput
| Module | Reads (ops/sec) | Writes (ops/sec) | Total (ops/sec) | Reasoning |
|---|---|---|---|---|
| Sales / POS | 8 – 12 | 2 – 4 | 10 – 16 | Highest load. Every cart action, item scan, stock reservation, and checkout hits the DB. Atomic stock reservation on every line item. |
| Inventory | 3 – 5 | 0.5 – 1 | 3.5 – 6 | Stock-level lookups on every product view + sale. Adjustments are rare but write-heavy. |
| Products | 2 – 4 | 0.1 – 0.3 | 2.1 – 4.3 | Catalog browsing & barcode lookup are frequent. Edits are rare. |
| Customers | 1 – 2 | 0.2 – 0.5 | 1.2 – 2.5 | Lookups during checkout. New customer creation is occasional. |
| Batches | 0.5 – 1 | 0.1 – 0.2 | 0.6 – 1.2 | Batch lookup during sales; expiry scans are periodic. |
| Dashboard | 0.2 – 0.5 | 0 | 0.2 – 0.5 | Periodic refresh on home page. Mostly aggregated reads. |
| Reports | 0.1 – 0.5 | 0 | 0.1 – 0.5 | On-demand, heavy aggregation queries. Often cached. |
| Alerts | 0.2 – 0.5 | 0.05 – 0.1 | 0.25 – 0.6 | Polling for in-app notifications; occasional dispatch events. |
| Staff | 0.1 – 0.3 | 0.05 – 0.1 | 0.15 – 0.4 | Worker listing, attendance pings. |
| Stores | 0.1 – 0.3 | 0.01 | 0.11 – 0.31 | Store switcher on multi-outlet tenants. |
| Expenses | 0.05 – 0.1 | 0.02 | 0.07 – 0.12 | Rare writes; reads only when viewing expense reports. |
| Bank | 0.05 | 0.02 | 0.07 | Occasional transactions; mostly on reconciliation. |
| Suppliers | 0.05 | 0.01 | 0.06 | Rarely edited; rarely read outside purchase flows. |
| Auth | 0.5 – 1 | 0.1 – 0.3 | 0.6 – 1.3 | Login, JWT verification, session refresh, lockout checks. |
| Profile | 0.05 | 0.01 | 0.06 | Rare reads & saves. |
| Sessions | 0.1 – 0.3 | 0.05 | 0.15 – 0.35 | Active-session listing, periodic refresh. |
| Subscription | 0.01 | 0.005 | 0.015 | Checked on every protected request; cached aggressively. |
| Calculator | 0 | 0 | 0 | Client-only. No DB traffic. |
| Barcode scan | 1 – 2 | 0 | 1 – 2 | Each scan triggers a product lookup. |
👤 Per-User Ops / sec
Each role drives a different mix of modules. Click a tab to see the DB load attributable to a single active user of each type, plus the per-endpoint breakdown of which APIs they primarily hit.
| Endpoint | Calls/min | Calls/sec |
|---|---|---|
GET /api/super-admin/track-map | 0.1 – 0.5 | 0.002 – 0.008 |
GET /api/super-admin/admins | 0.1 – 0.3 | 0.002 – 0.005 |
GET /api/super-admin/activity | 0.1 – 0.3 | 0.002 – 0.005 |
GET /api/super-admin/settings/owner-defaults | 0.05 – 0.1 | 0.001 – 0.002 |
POST /api/super-admin/admins | 0.01 – 0.05 | 0.0002 – 0.001 |
PATCH /api/super-admin/admins/{id}/status | 0.01 – 0.05 | 0.0002 – 0.001 |
POST /api/super-admin/admins/{id}/reset-password | 0.01 – 0.03 | 0.0002 – 0.0005 |
POST /api/super-admin/owners/{id}/transfer | 0.03 – 0.15 | 0.0005 – 0.003 |
/api/auth/me | 60 – 300 | 1 – 5 |
POST /api/auth/refresh | 6 – 30 | 0.1 – 0.5 |
Module breakdown: Admin management ~0.3 ops/sec · Track Map ~0.5 ops/sec · Activity log ~0.3 ops/sec · Platform settings ~0.1 ops/sec · Module grants ~0.1 ops/sec · Auth/sessions ~1.5 ops/sec.
| Endpoint | Calls/min | Calls/sec |
|---|---|---|
GET /api/admin/owners/{owner_id}/stats | 0.5 – 2 | 0.008 – 0.033 |
GET /api/users/owners | 1 – 5 | 0.017 – 0.083 |
POST /api/users/owners | 0.01 – 0.05 | 0.0002 – 0.001 |
GET /api/subscriptions/owners | 0.5 – 2 | 0.008 – 0.033 |
POST /api/subscriptions/owners/{id}/grant | 0.05 – 0.2 | 0.001 – 0.003 |
GET /api/modules/owners/{id}/grants | 0.5 – 2 | 0.008 – 0.033 |
PUT /api/modules/owners/{id}/grants | 0.01 – 0.1 | 0.0002 – 0.002 |
POST /api/alerts/send | 0.05 – 0.2 | 0.001 – 0.003 |
GET /api/alerts/logs | 0.1 – 0.5 | 0.002 – 0.008 |
POST /api/expenses | 0.05 – 0.3 | 0.001 – 0.005 |
GET /api/expenses | 0.5 – 3 | 0.008 – 0.05 |
/api/auth/me | 60 – 300 | 1 – 5 |
POST /api/auth/refresh | 6 – 30 | 0.1 – 0.5 |
Module breakdown: Owner onboarding ~0.4 ops/sec · Module access ~0.4 ops/sec · Owner stats ~0.5 ops/sec · Alerts ~0.4 ops/sec · Subscriptions ~0.3 ops/sec · Activity log ~0.3 ops/sec · Expenses ~0.1 ops/sec · Auth/sessions ~1.5 ops/sec.
| Endpoint | Calls/min | Calls/sec |
|---|---|---|
POST /api/sales/checkout | 6 – 40 | 0.1 – 0.7 |
GET /api/sales | 5 – 30 | 0.08 – 0.5 |
GET /api/products | 10 – 80 | 0.17 – 1.3 |
GET /api/products/{id} | 10 – 80 | 0.17 – 1.3 |
GET /api/inventory | 5 – 30 | 0.08 – 0.5 |
GET /api/inventory/summary | 2 – 15 | 0.03 – 0.25 |
GET /api/inventory/movements | 2 – 15 | 0.03 – 0.25 |
GET /api/customers | 5 – 30 | 0.08 – 0.5 |
GET /api/customers/{id} | 5 – 30 | 0.08 – 0.5 |
GET /api/customers/{id}/ledger | 1 – 6 | 0.017 – 0.1 |
GET /api/customers/khata/summary | 2 – 12 | 0.03 – 0.2 |
GET /api/batches | 1 – 6 | 0.017 – 0.1 |
GET /api/batches/alerts | 0.5 – 3 | 0.008 – 0.05 |
GET /api/reports/dashboard | 1 – 5 | 0.017 – 0.083 |
GET /api/reports/sales | 0.5 – 3 | 0.008 – 0.05 |
GET /api/reports/profit-loss | 0.2 – 1 | 0.003 – 0.017 |
GET /api/reports/inventory | 0.2 – 1 | 0.003 – 0.017 |
GET /api/reports/customers | 0.1 – 0.5 | 0.002 – 0.008 |
GET /api/reports/staff-performance | 0.1 – 0.5 | 0.002 – 0.008 |
GET /api/reports/stores-comparison | 0.1 – 0.5 | 0.002 – 0.008 |
POST /api/batches | 0.2 – 2 | 0.003 – 0.033 |
POST /api/inventory/{id}/move | 0.5 – 5 | 0.008 – 0.083 |
POST /api/bank/transactions | 0.5 – 5 | 0.008 – 0.083 |
GET /api/bank/accounts | 1 – 6 | 0.017 – 0.1 |
GET /api/bank/transactions | 1 – 8 | 0.017 – 0.133 |
POST /api/staff/attendance/checkin | 0.5 – 4 | 0.008 – 0.067 |
POST /api/staff/attendance/checkout | 0.5 – 4 | 0.008 – 0.067 |
GET /api/staff/directory | 1 – 5 | 0.017 – 0.083 |
GET /api/stores | 0.5 – 3 | 0.008 – 0.05 |
GET /api/users/me | 60 – 300 | 1 – 5 |
POST /api/auth/refresh | 6 – 30 | 0.1 – 0.5 |
Hot path: POST /api/sales/checkout drives 0.1 – 0.7 ops/sec and fans out to inventory + customer reads. Atomic stock reservation on every line item. Reports rate-limited 60/min/user.
| Endpoint | Calls/min | Calls/sec |
|---|---|---|
POST /api/sales/checkout | 5 – 30 | 0.08 – 0.5 |
GET /api/sales | 5 – 30 | 0.08 – 0.5 |
PUT /api/sales/{id} | 0.1 – 1 | 0.002 – 0.017 |
GET /api/products | 5 – 30 | 0.08 – 0.5 |
GET /api/products/{id} | 5 – 30 | 0.08 – 0.5 |
GET /api/products/categories | 1 – 8 | 0.017 – 0.133 |
GET /api/products/summary | 1 – 8 | 0.017 – 0.133 |
GET /api/products/brands | 1 – 8 | 0.017 – 0.133 |
GET /api/products/reorder | 0.5 – 4 | 0.008 – 0.067 |
GET /api/customers | 5 – 30 | 0.08 – 0.5 |
GET /api/customers/{id} | 5 – 30 | 0.08 – 0.5 |
POST /api/customers | 0.5 – 5 | 0.008 – 0.083 |
GET /api/customers/{id}/ledger | 1 – 6 | 0.017 – 0.1 |
GET /api/customers/khata/summary | 2 – 12 | 0.03 – 0.2 |
GET /api/inventory | 5 – 30 | 0.08 – 0.5 |
GET /api/inventory/summary | 2 – 15 | 0.03 – 0.25 |
GET /api/inventory/movements | 2 – 15 | 0.03 – 0.25 |
POST /api/inventory/{id}/move | 0.5 – 5 | 0.008 – 0.083 |
POST /api/inventory/transfer | 0.1 – 1 | 0.002 – 0.017 |
GET /api/batches | 1 – 6 | 0.017 – 0.1 |
GET /api/batches/alerts | 0.5 – 3 | 0.008 – 0.05 |
GET /api/batches/by-product/{id} | 0.5 – 3 | 0.008 – 0.05 |
POST /api/batches | 0.2 – 2 | 0.003 – 0.033 |
GET /api/users/me | 60 – 300 | 1 – 5 |
POST /api/auth/refresh | 6 – 30 | 0.1 – 0.5 |
Hot path: POST /api/sales/checkout is the worker primary driver. Cannot access admin-only or owner-only routes (inventory writes, reports, alerts, staff, bank, stores).
| Endpoint | Calls/min | Calls/sec |
|---|---|---|
POST /api/auth/login | 0.5 – 5 | 0.008 – 0.083 |
POST /api/auth/forgot-password | 0.05 – 0.3 | 0.001 – 0.005 |
POST /api/auth/reset-password | 0.05 – 0.3 | 0.001 – 0.005 |
POST /api/auth/register | 0.01 – 0.1 | 0.0002 – 0.002 |
GET / | 0.5 – 5 | 0.008 – 0.083 |
GET /health | 0.5 – 5 | 0.008 – 0.083 |
Public endpoints only. Login rate-limited 10/min/IP; lockout after failed attempts. No JWT required.
📦 User-to-Tenant Multiplier
| Scenario | Users active | Ops / sec (DB) | Notes |
|---|---|---|---|
| 1 owner + 1 worker, quiet | 2 | ~2 – 5 | Mostly owner dashboard + worker idle. |
| 1 owner + 2 workers, busy | 3 | ~25 – 60 | Workers doing POS, owner reviewing reports. |
| 1 owner + 3 workers, peak | 4 | ~50 – 110 | 3 active counters + owner. |
| 1 admin managing 10 owners | 11 | ~15 – 35 | Admin idle, owners split across platform. |
| 1 super admin managing 5 admins | 6 | ~5 – 15 | Mostly management views. |
🧮 Aggregate Throughput
| Scenario | Writes / sec | Reads / sec | Total / sec | Notes |
|---|---|---|---|---|
| Single shop, idle | 0.1 – 0.3 | 1 – 3 | 1 – 3 | Dashboard polling, auth pings, alert checks. |
| Single shop, busy | 3 – 6 | 15 – 25 | 18 – 31 | One active counter, frequent scans, periodic reports. |
| Single shop, peak hour | 5 – 10 | 25 – 40 | 30 – 50 | Multiple counters, batch entry, real-time report refresh. |
| Platform (10k tenants, 10% active) | 500 – 1,000 | 2,500 – 4,000 | 3,000 – 5,000 | Sharded across MongoDB cluster. owner_id is the shard key. |
🚀 Hotspot Write Collections
sales— peak 2 – 4 writes/sec per shop. Indexed byowner_id,created_at,store_id,customer_id.stock_movements— 1 – 3 writes/sec per shop from atomic stock reservation.audit_log&admin_activity— bursty, low-rate but append-heavy.sessions— periodic refresh on every protected request.
🔌 Backend Mitigations
- Async Motor driver — non-blocking I/O across thousands of concurrent ops.
- Compound indexes on
(owner_id, created_at)for tenant-scoped queries. - React Query cache on the frontend — deduplicates reads within TTL.
- Rate limiting (slowapi) — bounds burst spikes per IP.
- Connection pooling on MongoDB Atlas.
- Webhook & alert dispatch moved off the request path where possible.
📋 Module Catalog (Reference)
Authoritative module list lives in backend/app/models/module.py.
System Modules (always on, FR-003)
Business Modules (per-tenant toggleable, FR-002)
Admin Modules (superadmin-grantable to plain admins)
🎬 Demo Flow Suggestions
A typical demo could walk through:
- Public → Register / Login as a new user.
- Super Admin → Bootstrap, create Admin, review Track Map.
- Admin → Create Owner (tenant), grant modules, send welcome alert, renew subscription.
- Owner → Add products, configure print settings, add workers, set per-worker modules, perform a sale, view reports.
- Worker → Login, scan barcode, complete a sale, view own sales history.
- Owner → View worker activity in reports, run P&L, manage inventory alerts.