A full-stack parcel delivery system with three role-based portals (Customer Β· Rider Β· Admin),
real Stripe payments, Firebase JWT auth, live tracking, and a 16-query parallel MongoDB
aggregation engine β covering all 64 districts of Bangladesh.
| Role | Password | Suggested flow | |
|---|---|---|---|
| π€ Customer | admin4@gmail.com |
123456aA |
Book parcel β pay β watch status update live |
| π΅ Rider | admin11@gmail.com |
123456aA |
Open task queue β confirm pickup β deliver β earnings update |
| π‘οΈ Admin | admin1@gmail.com |
123456aA |
Approve a rider β assign a delivery β explore the KPI dashboard |
π³ Stripe test card
4242 4242 4242 4242 Β· Any future expiry Β· Any CVC
Stripe test mode β no real charge, ever.
Most portfolio apps stop at a UI with mock data. This one doesn't.
| What it does | Why it matters |
|---|---|
| Server-side pricing validation | Parcel cost is recalculated on the backend and compared to the client value. Mismatch β 400. Price tampering is impossible. |
| Firebase JWT on every route | firebase-admin decodes and verifies tokens server-side. Role is checked from MongoDB β not the token claim. A modified token does nothing. |
| 16 parallel MongoDB aggregations | The admin overview fires all KPI queries inside a single Promise.all(). Zero sequential waterfalls, one round-trip. |
| Full Stripe PaymentIntents flow | Secret key never touches the client. Only the client_secret does. Webhook-ready payment recording. |
| Three purpose-built dashboards | Each role has a separate data model, API, and animated UI β not the same page with hidden tabs. |
π€ Customer Portal
| Feature | Detail |
|---|---|
| Parcel Booking | Multi-step form β document vs non-document, weight tiers, same/inter-district auto-pricing |
| Stripe Payment | Full PaymentIntent flow β card UI β confirmation β DB write β parcel marked paid |
| Live Tracking | Public page β unique PCL-YYYYMMDD-XXXXX ID, full event log with location + timestamp |
| Dashboard | Single API: stats, active parcel progress stepper, monthly spend bar chart, status donut |
| Payment History | Transaction IDs, amounts, dates |
π΅ Rider Portal
| Feature | Detail |
|---|---|
| Task Queue | Live assigned + in-transit parcels, colour-coded by delivery type |
| Pickup / Delivery | One-tap confirmation β status update β tracking event written to DB |
| Earnings Wallet | Lifetime / weekly / monthly breakdown, settled vs pending cashout |
| Commission | 80% same-district Β· 30% inter-district β shown inline, always visible |
| Dashboard | Profile card, active queue, route analysis chart, cashout nudge |
π‘οΈ Admin Command Centre
| Feature | Detail |
|---|---|
| KPI Overview | 16 parallel queries β revenue today/7d/30d, parcel counts, top districts, 7-day sparkline |
| Rider Approval | Review NID, bike, region β approve or reject inline |
| Rider Assignment | Filter by district β assign β rider phone shown for coordination |
| User Management | All users + last login + roles β promote to admin in one click |
React 19 + Vite 7
ββββββββββββββ¬βββββββββββββ¬βββββββββββββ
β Customer β Rider β Admin β
βββββββ¬βββββββ΄ββββββ¬βββββββ΄ββββββ¬βββββββ
ββββββββββββββΌβββββββββββββ
TanStack Query v5
(cache Β· stale-time Β· refetch)
β
Axios + Firebase JWT
β
Express 5 ββ verifyFBToken
β verifyAdmin
β verifyRider
β
MongoDB Atlas ββ $match Β· $group
Promise.all([...16])
β
users Β· parcels Β· riders Β· payments Β· tracking
| Tech | Version | Role | |
|---|---|---|---|
| Frontend | React, Vite, React Router | 19 Β· 7 Β· 7 | UI, routing, layouts |
| State | TanStack Query, React Hook Form | 5 Β· 7 | Server cache, forms |
| Styling | Tailwind CSS, DaisyUI | 4 Β· 5 | Utility-first, light/dark |
| Motion | Framer Motion, Recharts | 12 Β· 3 | Animations, charts |
| Payments | Stripe.js + Stripe Node | 8 Β· 20 | PaymentIntents, PCI |
| Auth | Firebase SDK + Admin SDK | 12 Β· 13 | Client auth + server JWT |
| Backend | Express, MongoDB Atlas | 5 Β· 7 | REST API, aggregations |
| Maps | React Leaflet | 5 | Coverage visualisation |
Document Same district ΰ§³60 Β· Inter district ΰ§³80
Non-Document Base β€ 3 kg: ΰ§³110 same / ΰ§³150 inter
Extra weight: +ΰ§³40 per kg above 3 kg
Inter surcharge: +ΰ§³40
Rider cut Same district 80% Β· Inter district 30%
Calculated client-side for UX, recalculated server-side for trust.
- Firebase Admin SDK verifies JWT on every protected route β forged tokens rejected
- Role stored in MongoDB β changing the token claim does nothing
- Email ownership enforced server-side β users can't read each other's data
- Rider role explicitly blocked from the role-promotion endpoint
- Stripe secret key is server-only β client only receives
client_secret
git clone https://github.com/Hridoykhan4/masakkali-client
git clone https://github.com/Hridoykhan4/masakkali-serverserver/.env
PORT=5000
DB_USER=
DB_PASS=
Stripe_KEY=sk_test_...
FB_SERVICE_KEY=base64_firebase_service_accountclient/.env.local
VITE_API_URL=http://localhost:5000
VITE_FIREBASE_API_KEY=
VITE_FIREBASE_AUTH_DOMAIN=
VITE_FIREBASE_PROJECT_ID=
VITE_FIREBASE_STORAGE_BUCKET=
VITE_FIREBASE_MESSAGING_SENDER_ID=
VITE_FIREBASE_APP_ID=
VITE_STRIPE_PK=pk_test_...cd masakkali-server && npm i && npm run dev
cd masakkali-client && npm i && npm run dev