Case Study: Maun Pharmacy
A complete pharmacy management platform with separate interfaces for customers, staff, and administrators, featuring real-time inventory synchronization and prescription workflows across web and mobile.

Role: Full-Stack Developer
Timeline: [add timeline]
Stack: Node.js, Express, PostgreSQL, Supabase, Socket.IO, React, React Native
Live Site: https://www.maunpharmacy.com/
Repo: https://github.com/maumaun30/CM-Pharmacy-API
Overview
Maun Pharmacy is a multi-platform system built to handle the operational complexity of a modern pharmacy. The architecture splits into four distinct codebases: a REST API backend, a customer-facing web UI, an admin dashboard, and a mobile application for on-the-go access. All four pieces work together to manage inventory, prescriptions, sales, and customer records in real-time.
The backend API handles authentication, business logic, and database operations through Supabase-managed PostgreSQL. Real-time updates propagate via Socket.IO to keep inventory levels and prescription statuses synchronized across all connected clients.
The Challenge
Pharmacies operate under tight regulatory requirements and zero tolerance for inventory errors. A medication going out of stock unnoticed can delay critical prescriptions. Staff need instant visibility into stock levels while processing sales, and administrators need oversight of multiple metrics without manual data reconciliation.
The system needed to serve three distinct user groups with different access levels and workflows: customers checking prescription status and browsing products, pharmacy staff processing sales and managing stock, and administrators monitoring business performance. Each group required a tailored interface, but all had to work from the same real-time data source.
What I Built
REST API with Real-Time Sync
The Express-based API provides endpoints for authentication, inventory management, prescription handling, and sales transactions. JWT tokens secure routes with role-based access control—customers, staff, and admins see different data scopes.
Supabase manages the PostgreSQL database and handles row-level security policies. I wrote custom PL/pgSQL functions for complex operations like prescription validation and inventory deduction with atomic transactions. Socket.IO broadcasts inventory changes and prescription updates to all connected clients the moment transactions complete.
Rate limiting and helmet middleware protect against abuse. Compression middleware reduces payload sizes for mobile clients on slower connections.
Customer Web Interface
The web UI lets customers browse the medication catalog, view prescription histories, and check order statuses. I built it with React to maintain responsive performance as the product catalog grows. Real-time Socket.IO listeners update prescription statuses without page refreshes.
The interface uses Supabase's client library for direct queries on non-sensitive data, reducing API load for read-heavy operations like product searches.
Admin Dashboard
Administrators get a separate React application with analytics views, inventory management tools, and user administration. The dashboard connects to the same API but accesses admin-scoped endpoints. Real-time charts update as sales occur, and low-stock alerts appear immediately when inventory thresholds are crossed.
I implemented batch operations for common tasks like adjusting prices across product categories or marking multiple prescriptions as filled.
Mobile Application
The React Native app gives staff mobility within the pharmacy—they can check stock, scan barcodes, and process simple transactions without returning to a desktop terminal. The same JWT authentication and Socket.IO connections work across platforms.
I optimized API responses for mobile bandwidth constraints and implemented offline-first patterns for viewing cached inventory data when connectivity drops.
Technical Highlights
Real-time synchronization required careful state management. When a staff member processes a sale that depletes inventory, the Socket.IO server broadcasts the updated count to all connected clients. Each client updates its local state, preventing stale data from causing overselling.
PL/pgSQL functions handle complex inventory operations atomically:
CREATE OR REPLACE FUNCTION process_sale(
p_items jsonb,
p_customer_id uuid
)
RETURNS TABLE(sale_id uuid, total numeric) AS $$
DECLARE
v_sale_id uuid;
v_item record;
BEGIN
INSERT INTO sales (customer_id, created_at)
VALUES (p_customer_id, NOW())
RETURNING id INTO v_sale_id;
FOR v_item IN SELECT * FROM jsonb_to_recordset(p_items)
AS (product_id uuid, quantity int)
LOOP
UPDATE inventory
SET quantity = quantity - v_item.quantity
WHERE product_id = v_item.product_id
AND quantity >= v_item.quantity;
IF NOT FOUND THEN
RAISE EXCEPTION 'Insufficient inventory for product %', v_item.product_id;
END IF;
INSERT INTO sale_items (sale_id, product_id, quantity)
VALUES (v_sale_id, v_item.product_id, v_item.quantity);
END LOOP;
RETURN QUERY
SELECT v_sale_id, SUM(si.quantity * p.price)
FROM sale_items si
JOIN products p ON p.id = si.product_id
WHERE si.sale_id = v_sale_id
GROUP BY v_sale_id;
END;
$$ LANGUAGE plpgsql;
This function ensures inventory never goes negative and all related records update together or roll back on failure.
The multi-repo architecture keeps concerns separated. The API repo contains no UI code, making it easier to version backend logic independently. When mobile and web clients need API changes, I update the Express routes and redeploy without touching client codebases.
Bcrypt hashing protects user passwords, and environment variables keep database credentials out of source control. Dayjs handles timezone conversions for prescription timestamps—critical when prescriptions have expiration dates.
Outcome
The system runs in production at maunpharmacy.com with [add outcome details: number of daily transactions, inventory items managed, user count, or operational improvements]. Real-time updates eliminated the need for manual stock checks between terminals. The mobile app lets staff verify inventory while restocking shelves, catching discrepancies immediately rather than during monthly audits.
The separation into four repositories proved maintainable—I can deploy API fixes without rebuilding client applications, and UI updates don't require backend coordination unless contracts change.
Screenshots

