A full-stack retail management platform covering authentication, inventory, sales, and reporting for day-to-day store operations. Built for a menswear retailer as part of ongoing freelance work.
| Admin Dashboard | Finances |
|---|---|
![]() |
![]() |
| Inventory | Sales (POS) |
| --- | --- |
![]() |
![]() |
- Authentication — JWT-based login signed with
HS256, tokens expiring after24h. Passwords hashed with bcrypt (10 salt rounds). Role-based access:AdminandSalesroles enforced at every protected endpoint. - Security — CORS restricted in production to origins set via
ALLOWED_ORIGINSenv var (defaults tohttp://localhost:5173andhttp://localhost:3000in development); security headers set manually (X-Content-Type-Options: nosniff,X-Frame-Options: DENY,X-XSS-Protection: 1; mode=block,Strict-Transport-Securityin production). Nohelmetdependency — headers are applied via custom Express middleware. - Point-of-Sale — sales-rep-facing POS page: search store inventory,
add items to cart, apply loyalty-point discounts, and complete checkout
(creates a
Salesrecord and decrements inventory count). - Sales analytics — total revenue, transaction count, and top-category summary cards; Recharts PieChart for revenue by category; Recharts BarChart for top-10 items by revenue; Recharts LineChart for daily revenue over time; full transaction table with date/time, sales rep, SKU, price, discount, and final price.
- Inventory management — tabbed view (General / Store / Warehouse); add
new stock (creates a
PurchaseStockrecord and upsertsInventory); edit existing items (price, count, supplier, etc.); delete SKUs; migrate units from Warehouse → Store; low-stock alert panel (threshold: 10 units). - Finances — revenue / cost / payment-pending / net cash-flow summary cards; Recharts LineChart for cash-flow overview and daily revenue; pending-payments list with inline payment entry; all-expenses and all-income tabs.
- Loyalty customers — register customers, accrue loyalty points per sale, apply points as discounts at checkout.
- User management (Admin only) — create/edit/delete staff accounts with
AdminorSalesroles. - Audit log — every action (login, sale, stock change, etc.) written to
the
Logtable with actor name, role, action text, and timestamp. - Settings — configurable company name (reflected in the POS page title and UI header in real time via a custom DOM event).
Core tables (SQLite):
| Table | Key columns |
|---|---|
Inventory |
SKU (PK), Category, ItemName, Count, Location (Store/Warehouse), Price, SupplierName, LastModified |
Sales |
Id, SalesRepName, SKU, Category, ItemName, Price, Timestamp, CustomerId, PointsApplied, Discount, FinalPrice |
PurchaseStock |
Id, SKU, Category, ItemName, Count, Location, SupplierName, Cost, AmountPaid, Pending (computed) |
LoyaltyCustomers |
CustId, Name, Phone, Email, LoyaltyPoints, MemberSince |
Finances |
Id=1 singleton — Revenue, Cost, PaymentPending, CashFlow (computed) |
User |
Id, Name, Role (Admin/Sales), Username, Password (bcrypt) |
Log |
Id, Name, Role, Action, Timestamp |
Settings |
Id=1 singleton — CompanyName |
Node.js · Express · React (Vite) · SQLite3 · JWT · Recharts · bcrypt · CORS
# Server
cd server
npm install
# Client
cd ..\client
npm installcd ..\server
Copy-Item .env.example .env
# Edit .env and set JWT_SECRET (minimum 32 characters)
# Generate a strong secret:
-join ((48..57) + (65..90) + (97..122) | Get-Random -Count 64 | % {[char]$_})Terminal 1 — Backend:
cd server
node server.jsTerminal 2 — Frontend:
cd client
npm run dev- Frontend: http://localhost:5173
- API: http://localhost:3000
Default login: username admin, password Admin@123
(change immediately after first login)
cd client
npm run buildThe Express server serves the built frontend from client/dist/ in
production mode.
NODE_ENV=production
PORT=3000
JWT_SECRET=<your-64-character-random-string>
ALLOWED_ORIGINS=https://yourdomain.example.comretail-management-system/
├── server/
│ ├── server.js # Express server, all API routes
│ ├── db.js # SQLite init, schema, query helpers
│ ├── auth.js # JWT sign/verify, bcrypt, requireAuth/requireAdmin middleware
│ ├── .env.example # Environment variable template
│ ├── seed-data.js # Demo seed (inventory + customers)
│ └── package.json
├── client/
│ ├── src/
│ │ ├── Admin.jsx # Admin shell + bottom navigation
│ │ ├── Sales.jsx # POS (sales-rep) page
│ │ ├── Login.jsx # Login form
│ │ └── components/
│ │ ├── admin/ # InventoryView, SalesView, FinancesView, CustomersView, UsersView, LogsView, SettingsView
│ │ └── shared/ # DataTable, Chart (Line), BarChart, PieChart, Modal, TabNav, CheckoutModal
│ ├── package.json
│ └── vite.config.js
├── .gitignore
├── package.json # Root (concurrent dev script)
└── README.md
- Change the default admin password (
Admin@123) immediately after first login. - Use a strong, random
JWT_SECRET(64+ characters recommended). - Set
NODE_ENV=productionin production — this enforces strict CORS and exits the process ifJWT_SECRETis missing or weak. .env,*.db, andnode_modules/are excluded from git via.gitignore.- A
.env.exampletemplate is committed instead of the real.env.
netstat -ano | findstr :3000
taskkill /F /PID <PID>cd server
Remove-Item database.db
# Restart server — DB and default admin are recreated automaticallycd client
Remove-Item -Recurse dist
Remove-Item -Recurse node_modules\.vite
npm run buildReady to go! 🚀



