A production-ready POS and inventory management system built for commercial kitchens. It handles real-time stock deductions, batch recipe tracking, and automated low-stock alerts.
Commercial kitchens and multi-branch restaurants often struggle with:
- Blind spots in inventory: Relying on manual end-of-day counts instead of real-time tracking, leading to unexpected stockouts.
- Bad accountability & theft: Without a unified digital ledger and strict audit trails, management struggles to prevent employee theft, identify discrepancies, or properly oversee daily cash flows and material usage.
- Complex recipe deduction: When cooking large batches (e.g., 20 liters of soup), accurately deducting individual raw ingredients (salt, tomatoes, oil) from the main store is a logistical nightmare.
- Order chaos & miscommunication: Relying on waiters shouting orders or dropping handwritten notes to the kitchen causes friction, wrong orders, and poor customer tracking.
- Alert fatigue: Getting pinged for every single low-stock item instead of receiving clean, batched summaries.
PasmenPasara POS v3 solves these issues by splitting the architecture into specialized React frontends communicating with a single Django REST API. We use Celery and Redis in the background to handle the heavy lifting: cascading inventory deductions based on recipe multipliers and batching low-stock alerts via WhatsApp.
To improve accountability and workflow, the system enforces a strict Dual-Receipt Flow: cashiers ring up the order and the system automatically prints two thermal receipts. One acts as the kitchen ticket, and the other is kept by the customer. When the food is ready, the customer's name is called and verified against their receipt—eliminating the need for complex, error-prone waiter apps.
Watch the full system breakdown and demo on YouTube:
Timestamps:
- 0:00 Introduction
- 1:17 Pain points
- 1:49 Cashier role overview
- 3:00 Dashboard walkthrough
- 3:30 Raw items setup
- 4:30 Stock management
- 6:00 Wastage & adjustments
- 7:00 Low-stock alerts
- 8:00 Production / recipes
- 11:00 Menu & dish setup
- 13:00 Recipes to dishes
- 15:00 Pricing & variations
- 17:00 Customizations / options
- 19:00 Linking dishes to options
- 20:00 User & role management
- 21:30 Branch management
- 22:30 Suppliers & purchases
- 26:00 POS order flow (cashier)
- 28:00 Order editing & status
- 29:30 Checkout & payment
- 31:00 Kitchen cook log
- 33:00 Inventory deduction
- 35:00 Analytics & reporting
- 37:00 Alerts & notifications
- 38:30 Mobile responsiveness
- 38:54 Wrap-up
The system natively supports thermal receipt printing at checkout. It automatically generates a kitchen ticket and a customer copy for order verification.
Click the image above to watch it in action.
The POS system actively being used in a real restaurant workflow:
Click the image above to watch it in action.
- Specialized Micro-Frontends: Separate React/Vite applications tailored for specific user roles (Cashier POS, Inventory Managers, System Admins). (Note: The mobile waiter app has been deprecated in favor of the more reliable dual-receipt cashier flow).
- Comprehensive Audit Logging: Custom Django middleware intercepts and logs every state-mutating API call (
POST/PATCH/DELETE), tracking the user ID, endpoint, IP address, and payload. This provides management with a tamper-proof ledger to enforce accountability.
- Batch Recipe Deduction: When kitchen staff logs a cooked batch, the system dynamically calculates raw ingredient usage based on predefined recipes and deducts it from the main store.
- Production Reversal (Undo): Reversing a batch log automatically recalculates and restores the exact quantities of raw ingredients back into the inventory.
- Cross-Branch Disbursements via Nginx/Ngrok: Built-in logic to handle the transfer of raw materials between branches. When a disbursement is initiated, the backend dispatches a request that routes through the Nginx/Ngrok network to hit the receiving branch's inventory update endpoint, keeping stock levels synced across locations.
- Smart WhatsApp Alerts: A Celery Beat cron job checks stock levels every 15 minutes. It aggregates low-stock and out-of-stock items and sends a single WhatsApp alert via the Twilio API.
- Global Alert Cooldowns: A buffer system prevents notification spam during rapid stock fluctuations or system restarts.
- Nightly Revenue Summaries: Automated end-of-day reports detailing total revenue, order counts, and critical stock warnings sent directly to management.
We containerized the entire stack using Docker and Docker Compose.
graph TD
%% Clients
OrderApp["Cashier POS<br/>React + TS + shadcn/ui<br/>Port 82"]
InventoryApp["Inventory Manager App<br/>React + TS + Tailwind<br/>Port 81/84"]
AdminDashboard["POS Admin Panel<br/>React + TS<br/>Port 83"]
%% API Gateway / Nginx
Nginx["Nginx Reverse Proxy / Load Balancer"]
%% Backend Services
subgraph "Backend Services"
Django["Django REST API / Gunicorn"]
Redis[("Redis Cache & Broker")]
Celery["Celery Task Worker"]
CeleryBeat["Celery Beat Scheduler"]
Postgres[("PostgreSQL DB")]
end
%% External Nodes & APIs
Twilio["Twilio WhatsApp API"]
OtherBranches["Other Branch APIs<br/>via Ngrok/Nginx"]
%% Data Flow Connections
OrderApp --> Nginx
InventoryApp --> Nginx
AdminDashboard --> Nginx
Nginx -->|Routes API Requests| Django
Django --> Postgres
Django -->|Enqueues Tasks| Redis
Django -.->|Disbursement Update| Nginx
Nginx -.->|Cross-Branch Request| OtherBranches
Redis --> Celery
CeleryBeat -->|Triggers Every 15m| Redis
Celery -->|Queries Data| Postgres
Celery -->|Dispatches Alerts| Twilio
Backend
- Python, Django 5, Django REST Framework (DRF)
- PostgreSQL 15
- Celery, Redis
- JWT Authentication (SimpleJWT)
- Twilio API (WhatsApp Business)
Frontend
- React 18/19, TypeScript, Vite
- Tailwind CSS, shadcn/ui, Framer Motion
- React Query (@tanstack/react-query), Axios
- Recharts
Infrastructure
- Docker, Docker Compose
- Gunicorn, Nginx
- Ngrok (for webhook/external testing)
Ring Up → Print → Prep → Verify
- Ring Up: Cashier inputs the customer's name and order into the POS.
- Print: System prints two thermal receipts. One goes to the kitchen for prep, the other stays with the customer.
- Verify: When the order is ready, the kitchen alerts the front, the customer's name is called, and the order is verified against their receipt.
Input → Processing → Output
- Definition: Admin defines a
BatchNameand assigns aBatchProductionRecipemapping raw items (e.g., 5kg Tomatoes, 200g Salt). - Execution: Chef logs the cooking of 3 batches via the UI.
- Processing: Backend intercepts the POST request, multiplies the recipe by 3, checks current stock, and atomically updates
MainStoreRawItems. - Validation: If successful, a
BatchProductionLogis created and anActivityLogrecords the user action.
Cron → Evaluation → Aggregation → Dispatch
- Trigger:
Celery Beatfirescheck_stock_levels()every 15 minutes. - Evaluation: Queries PostgreSQL for all
RawItemswherequantity_in_stock <= reorder_level. - Aggregation: Compiles all flagged items into a single summary payload.
- Cooldown Check: Verifies if an alert was sent in the last 2 minutes to prevent spam.
- Dispatch: Pushes the payload to the Twilio API, updating the
last_whatsapp_sent_attimestamp.
- Docker and Docker Compose installed
- Twilio Account SID and Auth Token (for WhatsApp features)
Create a .env file in the root directory:
# Database
POSTGRES_DB=pasmenpasara_db
POSTGRES_USER=postgres
POSTGRES_PASSWORD=supersecretpassword
# Twilio Configuration
TWILIO_ACCOUNT_SID=your_account_sid
TWILIO_AUTH_TOKEN=your_auth_token
TWILIO_WHATSAPP_FROM=+1234567890
WHATSAPP_ADMIN_NUMBERS=+233555555555,+233200000000
BRANCH_NAME="Main Branch HQ"
# Frontend API Mapping
VITE_API_BASE_URL=http://localhost:8000Build and start all 6 containers:
docker compose up -d --buildRun Django migrations and create the initial administrator account:
docker compose exec web python manage.py migrate
docker compose exec web python manage.py createsuperuser- Core API:
http://localhost:8000 - Inventory Manager:
http://localhost:81/http://localhost:84 - Cashier POS:
http://localhost:82 - Admin Dashboard:
http://localhost:83
- Polymorphic Data Modeling: Handles the complexity of linking Sales and Adjustments to either standalone
Products,Customizables, orRawItemsusing DjangoUniqueConstraintsand customclean()validation methods. - Defensive Task Queuing: The Celery implementation uses global cooldowns and strict timestamp tracking (
last_whatsapp_sent_at) to ensure network failures or rapid worker restarts never result in duplicate WhatsApp messages. - Middleware-Driven Auditing: A custom
ActivityLogMiddlewarecleanly intercepts the request/response lifecycle, extracting the user session, parsing the JSON payload, and persisting a tamper-proof audit trail without cluttering views. - Optimized Frontend Bundles: Splitting the frontends into three distinct repositories reduces the bundle size for checkout devices while allowing heavy charting libraries (
Recharts) to exist solely on the admin dashboard.
- WebSockets for Kitchen Displays: Migrate the order queue from a polling architecture to real-time Server-Sent Events (SSE) or Django Channels (WebSockets) for instant Kitchen Display System (KDS) updates.
- Schema-Based Multi-Tenancy: Transition from logical branch separation to PostgreSQL schema-based multi-tenancy (using
django-tenant-schemas) to support true SaaS-level scalability. - Predictive Analytics: Introduce an ML microservice that analyzes historical
BatchProductionLogandSaledata to predict when raw materials will run out, rather than reacting to static reorder levels.


