07Inventory Management
Sajilo Inventory
A multi-tenant inventory app for small shops, with shop-scoped product catalogs, customizable product fields, stock movement history, low-stock and expiry indicators, and inventory counts with optional adjustments.

Context
The problem
Small retailers can have different product details to track—such as expiry dates for packaged goods or frame size and color for bicycles—alongside day-to-day stock control. Sajilo Inventory lets each shop configure its product fields while keeping its inventory records scoped to that shop.
Solution
How TeachMate works
Shop members sign in with Google and create or join a shop using an invite code. They can manage products and custom fields, record stock additions and removals, and reconcile inventory through stock takes. Dashboard indicators surface low stock and date-based attributes nearing expiry.
Capabilities
What it includes
- Shop-scoped product catalog with SKU/name search, pagination, and product CSV export
- Per-shop text, number, and date attributes for product-specific details
- Stock IN/OUT movements with movement history, CSV export, and insufficient-stock checks
- Dashboard indicators for low and out-of-stock products, inventory value, and upcoming expiry dates
- Stock takes compare counted and expected quantities, with optional adjustments recorded as movements
- Invite-code shop membership with owner-controlled member and financial-visibility settings
System design
Architecture
- Next.js App Router uses server-rendered pages and Server Actions for product, attribute, and stock workflows, plus route handlers for CSV exports.
- Prisma 7 with the PostgreSQL driver adapter persists tenant, product, custom-attribute, stock-movement, and stock-take data in PostgreSQL.
- Better Auth manages Google OAuth sessions; tenant access is checked in the request proxy, tenant layout, and Server Actions, with queries scoped to the tenant from the session.
- Zod validates shop, product, stock-movement, and custom-attribute input; Vitest covers Server Action behavior and tenant isolation scenarios.
Trade-offs
Engineering decisions
- Use shared database tables keyed by tenantId and tenant-slug routes so multiple shops can use one application while queries remain scoped to the signed-in user’s shop.
- Let each tenant define typed product attributes instead of hard-coding fields for a single retail category.
- Apply stock movements and quantity changes transactionally, and reject stock-out requests that exceed available inventory.
- Model stock takes as expected-versus-counted snapshots, with optional adjustments producing corresponding stock-movement records.