A full-stack Point of Sale web application built with React, Node.js, Express, and MySQL.
Frontend: React 18, Vite, Tailwind CSS, Recharts, React Router v6 Backend: Node.js, Express.js, MySQL2, JWT Authentication Payments: Paystack (test mode)
- Node.js v16 or later
- MySQL 8.0 or later
- npm v8 or later
- A Paystack account (free test keys at dashboard.paystack.com)
git clone <your-repo-url>
cd pos-systemLog into MySQL and create the database, then run the schema and seed files:
mysql -u root -pCREATE DATABASE pos_db;
EXIT;mysql -u root -p pos_db < server/database/schema.sql
mysql -u root -p pos_db < server/database/seed.sqlCopy the example file and fill in your values:
cp .env.example .envOpen .env and update:
PORT=5000
DB_HOST=localhost
DB_PORT=3306
DB_USER=root
DB_PASSWORD=your_mysql_password
DB_NAME=pos_db
JWT_SECRET=pick-a-strong-random-string
PAYSTACK_SECRET_KEY=sk_test_your_key_here
PAYSTACK_PUBLIC_KEY=pk_test_your_key_here# Backend
cd server
npm install
# Frontend
cd ../client
npm installOpen two terminal windows:
# Terminal 1 — Backend (runs on port 5000)
cd server
npm run dev
# Terminal 2 — Frontend (runs on port 5173)
cd client
npm run devThe frontend proxies API requests to http://localhost:5000, so both servers need to be running.
Visit http://localhost:5173 in your browser.
The seed data includes these accounts (all passwords are password123):
| Username | Role | Full Name |
|---|---|---|
| admin | Admin | Kofi Admin |
| manager1 | Manager | Ama Manager |
| cashier1 | Cashier | Kwame Cashier |
| cashier2 | Cashier | Abena Seller |
| cashier3 | Cashier | Yaw Teller |
pos-system/
├── client/ # React frontend (Vite)
│ ├── src/
│ │ ├── api/ # Axios instance + service modules
│ │ ├── components/ # Reusable UI, layout, POS, table components
│ │ ├── context/ # AuthContext, CartContext
│ │ ├── hooks/ # useAuth, useCart, useDebounce
│ │ ├── pages/ # Route pages (auth, dashboard, pos, etc.)
│ │ └── utils/ # Helpers (currency formatting, dates)
│ ├── tailwind.config.js
│ └── vite.config.js
├── server/ # Express backend
│ ├── config/ # Database connection pool
│ ├── controllers/ # (logic lives in route files)
│ ├── middleware/ # JWT auth + role-based access
│ ├── routes/ # 8 route modules
│ ├── utils/ # Paystack helper
│ ├── database/
│ │ ├── schema.sql # All CREATE TABLE statements
│ │ └── seed.sql # Sample data
│ └── server.js # Express entry point
├── .env.example
├── .gitignore
└── README.md
- Authentication — JWT login, role-based access (admin / manager / cashier)
- Products — Full CRUD, search, category filters, low-stock alerts
- Inventory — Stock levels, manual adjustments, automatic sale deductions, movement logs
- POS Screen — Product grid + cart, discount support, customer selection, fast checkout
- Payments — Cash handling with change calculation, Paystack integration for card/mobile money
- Customers — CRUD, purchase history, loyalty points (1 point per GH₵10 spent)
- Receipts — Printable thermal-style receipts for every transaction
- Reports — Sales overview, top products, inventory status, cashier performance with charts
The app uses Paystack Popup (inline JavaScript) for card and mobile money payments. In development, use Paystack test keys — no real charges are made.
- Sign up at paystack.com
- Copy your test public and secret keys from the dashboard
- Paste them into your
.envfile
When a customer pays by card or mobile money, the app initializes a transaction through the backend, opens the Paystack popup on the frontend, and verifies the payment on completion.
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| POST | /api/auth/login | Public | Log in, receive JWT |
| GET | /api/auth/me | Token | Current user profile |
| GET | /api/products | Token | List products (paginated) |
| POST | /api/products | Manager+ | Create product |
| PUT | /api/products/:id | Manager+ | Update product |
| DELETE | /api/products/:id | Admin | Deactivate product |
| GET | /api/inventory/logs | Manager+ | Inventory movement log |
| POST | /api/inventory/adjust | Manager+ | Manual stock adjustment |
| GET | /api/inventory/alerts | Manager+ | Low-stock alerts |
| POST | /api/sales | Token | Create sale (transaction) |
| GET | /api/sales | Token | List sales |
| GET | /api/sales/:id | Token | Sale details + items |
| POST | /api/payments/initialize | Token | Start Paystack payment |
| GET | /api/payments/verify/:reference | Token | Verify payment |
| GET | /api/customers | Token | List customers |
| POST | /api/customers | Token | Create customer |
| PUT | /api/customers/:id | Token | Update customer |
| DELETE | /api/customers/:id | Manager+ | Delete customer |
| GET | /api/reports/sales-summary | Manager+ | Revenue summary |
| GET | /api/reports/product-performance | Manager+ | Top-selling products |
| GET | /api/reports/inventory-status | Manager+ | Stock overview |
| GET | /api/reports/cashier-performance | Manager+ | Cashier stats |
| GET | /api/users | Admin | List users |
| POST | /api/users | Admin | Create user |
| PUT | /api/users/:id | Admin | Update user |
| DELETE | /api/users/:id | Admin | Deactivate user |
This project was built as a school project.