Small computer and electronics shops in Bangladesh run on paper ledgers or spreadsheets — no per-branch stock visibility, no warranty tracking on serialized parts like GPUs or SSDs, and no way to meter or bill for the SMS receipts they send customers. HisabOS needed to give one owner a tenant-isolated system across multiple branches, track warranty at the individual serial number rather than just the product, and turn SMS from an untracked cost into a metered, billable resource.
- 01Multi-branch sale counter — barcode scan, FIFO stock lots, held sales, customer returns
- 02Purchase bills with supplier ledgers and per-batch FIFO cost tracking
- 03Serialized inventory with per-unit warranty tracking and a full claim workflow (repair / replace / refund)
- 04SMS credit wallet — one-time free grant at signup, paid top-ups with an admin approval queue
- 05Role-based access (Super Admin / Shop Owner / Manager / Cashier) with per-terminal device binding
- 06Bilingual PDF invoices and receipts (thermal + A4, English + Bangla)
- 07Company settings — branding, logo upload, receipt customization
- 08Subscription billing with trial, grace-period, and suspension lifecycle
- 09Offline-capable PWA with a local sync queue for flaky counter connections
Backend and frontend evolved as two independent codebases, so contract drift was constant — the same API grew three different response envelope shapes across different modules over time, and the frontend had to mirror whatever was actually there, never assume consistency. Multi-tenant isolation had to be airtight: every query scoped by tenant, and a cross-tenant lookup returns 404, not 403, so it never leaks that another shop's record exists. FIFO cost accounting had to hold up across purchases, transfers, and returns without ever merging batches, so margin reporting stays accurate down to the unit. Every schema change had to land on a live database with real data in it, so migrations went through diff → inspect → execute, never the tool's own destructive reset path. And the SMS approval queue had to be transaction-safe against two admins clicking "approve" on the same order at once.
Two repositories. Backend: Express 5 and Prisma 7 on Postgres (Neon), organized as one folder per domain (routes/controllers/services/schema), Zod validation throughout, JWT access + refresh with silent renewal, and a subscription guard that computes a tenant's live grace-period state from stored dates rather than trusting a cached status flag. Frontend: React 19, Vite, TypeScript, Tailwind v4, TanStack Query for all server state, React Hook Form + Zod schemas mirroring the backend's exactly, feature-based folders, Framer Motion throughout, and a Dexie-backed offline outbox so the counter keeps working through a dropped connection.