Multi-warehouse inventory & order-processing system — batch + expiry control, FEFO dispatch, barcode/GS1 scanning, and live Google Sheets sync.
Built to replace manual Excel tracking for a wholesale/FMCG-style operation: stock truth across warehouses, first-expiry-first-out dispatch, and full order processing — all on Firebase's free tier.
A web-based control hub for running inventory and orders across multiple warehouses — with the kind of stock accuracy you need when you're dealing with batches, expiry dates, and dispatch.
- 📊 Inventory — SKU → multiple batches with expiry color-coding, FEFO ("dispatch first") ordering, per-location stock, and a 3D batch visualization.
- 📷 Scan & Add — SKU-first flow: scan a barcode / GS1 2D DataMatrix / QR label, OCR the expiry date, and save. GS1 codes auto-fill GTIN + batch + expiry.
- 🔄 Transfers → Receiving — Draft → Shipped → In-transit → Accepted/Mismatch, with stock atomically locked while in transit.
- 🧾 Orders — SKU-first with FEFO recommendation + override, cross-location fulfilment, and shipping plan.
- ↩️ Returns — verified add-back (only "Good" condition restocked).
- 📈 Analytics & Reports — KPIs, movers, demand, expiry-risk, order status, plus a reconciliation report (ledger vs stock) and vendor reorder list.
- 🗂️ Stock ledger — append-only audit of every movement.
- 📑 Google Sheets sync — live per-location stock tabs + monthly history, via an Apps Script web app.
| Role | Access |
|---|---|
| Admin | Everything — all locations, ledger, import/export, users, settings |
| Manager | All locations (orders/transfers/stock/returns), no admin-only settings |
| User | Only their assigned warehouse(s) |
Enforced in Firestore security rules — role- and location-gated, ledger append-only, transfers read-scoped.
| Layer | Stack |
|---|---|
| Frontend | React 18 + Vite, React Router, Framer Motion, Recharts, Three.js (@react-three/fiber + drei) |
| Scanning | @zxing (barcode + GS1 2D DataMatrix) + tesseract.js OCR (expiry) + QR labels |
| Backend | Cloud Firestore (single source of truth) + Firebase Auth + Firebase Hosting |
| Sync | Google Apps Script web app (per-task workbooks) |
| Cost | Runs comfortably on Firebase's free tier |
# Frontend
cd frontend
cp .env.example .env # fill in your Firebase web config
npm install
npm run dev # → http://localhost:5173Backend (Firestore rules / indexes / seed scripts) live in backend/:
cd backend
npm install
# Seed an admin user + sample data (set creds via env first):
ADMIN_EMAIL=you@example.com ADMIN_PASSWORD=yourpassword \
GOOGLE_CLOUD_PROJECT=your-firebase-project-id \
node scripts/seedAdmin.mjsThis repo is wired to a Firebase project named pmcinventoryhub (in .firebaserc). To deploy your own copy:
- Create a Firebase project at console.firebase.google.com — enable Authentication (Email/Password) and Firestore.
- Point this repo at it — edit
.firebasercand replacepmcinventoryhubwith your project ID:{ "projects": { "default": "your-firebase-project-id" } } - Add your web config — copy your Firebase web SDK config into
frontend/.env(seefrontend/.env.example). - Deploy:
cd frontend && npm run build && cd .. firebase deploy --only hosting,firestore:rules,firestore:indexes
- Seed an admin — run
backend/scripts/seedAdmin.mjswith your env vars (above).
The live demo above points at the original project. Once you redeploy to your own project, your URL becomes
https://<your-project-id>.web.app.
- No secrets in git —
.env, service-account keys, andserviceAccountKey.jsonare git-ignored. - Higher-accuracy OCR runs through a server proxy (no API key in the browser).
- Firestore rules enforce role + location scoping; the stock ledger is append-only.
- Console logs stripped in production builds.