ByteBites
Production-grade hyperlocal delivery — 6 microservices, RabbitMQ async payments, Socket.IO live rider tracking, Strategy-pattern coupon engine, geospatial dispatch, jsPDF receipts, Razorpay/Stripe & 4-role dashboards.

←Use arrow keys or swipe to navigate→
The Problem
Hyperlocal food delivery is one of the hardest consumer products to ship correctly. A customer expects geo-accurate restaurant discovery, transparent pricing, instant payment confirmation, and a live map showing a rider moving toward their door. A restaurant partner needs verified onboarding, a real-time order feed, and a kitchen workflow that cannot miss a single paid order. A delivery rider needs fair dispatch, earnings visibility, and GPS tools that broadcast location to the customer mid-trip. A platform admin needs verification gates, promotional tooling, and revenue analytics — all without touching production order code.
Most portfolio projects in this space stop at a single-role menu + cart demo. They bundle payments, sockets, and dispatch into one Express monolith; payment webhooks block HTTP threads; rider assignment is a manual API call; coupons are a hardcoded if (code === 'SAVE10') check. There is no message broker, no geospatial index strategy, no TTL cleanup for abandoned checkouts, and no honest capacity model for the deployed stack.
ByteBites exists to close that gap: a **standalone, production-grade food delivery platform** — four roles, six microservices, async payment fulfillment, Socket.IO live state, MongoDB 2dsphere proximity, and a formally designed coupon engine — deployed across Vercel, Render, AWS EC2, and MongoDB Atlas.
My Role & Constraints
Solo Full-Stack Engineer, Architect & Product Owner — I designed, implemented, documented, and deployed ByteBites end-to end.
**Product & frontend:** React 19 SPA (Vite, TypeScript, Tailwind CSS 4) with role-specific dashboards for Customer, Seller, Rider, and Admin. Built the landing page, OAuth onboarding, explore/discovery UI, restaurant menus, smart cart, Leaflet address picker, checkout with live fee preview, Razorpay + Stripe payment flows, live tracking map (OSRM + rider GPS), order history with reorder, jsPDF receipt export, review flows, Recharts analytics, and dark/light theming.
**Backend & distributed systems:** Six Node.js/Express 5 microservices — Auth (:5007), Restaurant (:5001), Utils (:5002), Realtime (:5004), Rider (:5005), Admin (:5006). Designed inter-service HTTP contracts, x-internal-key service auth, shared JWT model, RabbitMQ event schemas, Socket.IO room topology, and per-service rate limiting. Implemented the CouponEngine (Strategy/Factory/Facade/Repository/Validator), distance-aware pricing engine, dynamic ETA module, sequential rider dispatch consumer, and unpaid-order TTL cleanup.
**Infrastructure & ops:** Dockerfiles per service (multi-stage Node 22 Alpine), RabbitMQ on AWS EC2 via Docker, six Render Web Services, Vercel frontend CDN deploy, MongoDB Atlas with geospatial indexes, Cloudinary media, and environment-separated secrets. Authored ARCHITECTURE.md, VIVA_DOCUMENTATION.md, API reference, and a full platform demo video.
System Design / Architecture
ByteBites follows a **domain-driven microservices architecture** — each service owns a bounded context, communicates over HTTP + AMQP, and deploys independently.
1$Browser · React SPA (Vercel)2$REST + JWT │ │ Socket.IO3$┌────────────┼──────────┬───────┬───────┴────────┐4$▼ ▼ ▼ ▼ ▼5$Auth Restaurant Utils Rider Realtime 6 services6$:5007 :5001 :5002 :5005 :5004 on Render7$│ │ ▲ │ │ ▲8$│ │ └────────┴───────┴────────────────┘ internal emit9$│ │10$│ │ RabbitMQ (Docker on AWS EC2)11$│ └──▶ payment_event · order_ready_queue12$│13$└───────────────▶ MongoDB Atlas — 2dsphere + TTL indexes14$(+ Admin :5006 · Razorpay · Stripe · Cloudinary)
**System topology:** React SPA (Vercel) talks REST + JWT to Auth, Restaurant, Utils, Rider, and Admin; WebSocket + JWT to Realtime. Restaurant, Utils, and Rider publish/consume RabbitMQ on AWS EC2. Auth, Restaurant, Rider, and Admin persist to MongoDB Atlas. External integrations: Google OAuth, Cloudinary, Razorpay, Stripe, OpenStreetMap, Nominatim, OSRM.
**Auth service** — Google OAuth token exchange, HS256 JWT (15-day expiry), role assignment (customer / seller / rider), ban enforcement at login, authLimiter (20 logins / 15 min).
**Restaurant service (core domain)** — Restaurants with autoLocation 2dsphere index; menu CRUD; single-restaurant cart; saved addresses with map picker coordinates; order lifecycle; restaurant + rider reviews (unique per orderId); seller analytics. Internal routes for payment lookup, rider assignment, earnings proxy — all gated by INTERNAL_SERVICE_KEY. Consumes payment_event queue; publishes order_ready_queue.
**Coupon & Discount Engine** (services/restaurant/src/coupon/) — a modular LLD subsystem I designed with standard GoF patterns:
- CouponEngine (**Facade**) — single apply(code, context) entry for checkout and validation.
- CouponRepository (**Repository**) — findByCode(), incrementUsage() against MongoDB.
- CouponValidator — chain: active → not expired → min order → global usageLimit → per-user limit (paid orders with same couponId).
- DiscountStrategyFactory (**Factory**) → DiscountStrategy (**Strategy interface**).
- **Two strategies:** FlatDiscountStrategy (fixed ₹ off, capped at subtotal, e.g. FLAT50) and PercentWithCapStrategy (% off with maxDiscount ceiling, e.g. SAVE20 → 20% max ₹100).
- CouponError — typed errors with HTTP status codes.
- **Lifecycle:** POST /api/coupon/validate at checkout → POST /api/order/new stores couponId + discountAmount on pending order → RabbitMQ PAYMENT_SUCCESS consumer calls recordUsage() only after payment confirms — no premature redemption.
**Pricing engine** (orderPricing.ts, mirrored on frontend) — min order ₹50; delivery fee tiers ₹29 (≤2 km) / ₹39 (≤5 km) / ₹49 (>5 km), waived above ₹250 subtotal; ₹7 platform fee; ₹15 small-order surcharge (₹50–₹99); coupon discount subtracted; rider payout ceil(km) × ₹17.
**Utils service** — Cloudinary image upload; Razorpay order create/verify (INR, UPI, cards); Stripe checkout session (international). On verified payment, publishes durable PAYMENT_SUCCESS to payment_event — Utils responds to gateway immediately; Restaurant processes async.
**Realtime service** — Socket.IO with JWT in handshake.auth.token. Clients auto-join user:{id} and restaurant:{id}. Internal POST /api/v1/internal/emit broadcasts backend and rider-client events. Key events: order:new, order:update, order:rider_assigned, order:available, rider:location.
**Rider service** — Profile with 2dsphere location, admin isVerified gate, online/offline toggle. Consumes order_ready_queue; runs **sequential nearest-first dispatch**: $geoNear on verified + available riders within RIDER_DISPATCH_RADIUS_M → emit order:available to nearest → 10s accept window → on timeout, offer next rider. Accept flow calls Restaurant internal assign API + socket notify all parties.
**Admin service** — Native MongoDB driver (no Mongoose overhead): user list + ban/unban (self-ban blocked), restaurant/rider verification, coupon full CRUD (create/edit/toggle/delete), platform GMV analytics + 7-day chart + top restaurants.
**Customer journey (end-to-end):** Google login → role select → geo explore (~5 km, text + category filters) → restaurant page (menu, ratings, reviews) → cart (single-restaurant enforcement) → checkout (address, live coupon, fee breakdown) → Razorpay/Stripe pay → async placed via queue → socket-tracked status through kitchen → rider dispatch → **live tracking page**: OSRM route polyline + **real-time rider GPS dot** (rider:location stream after picked_up) + status-aware dynamic ETA → delivered → dual review prompt → **jsPDF receipt download** from order history → reorder supported.
**Order state machine:** placed → accepted → preparing → ready_for_rider → rider_assigned → picked_up → delivered (cancel allowed for customer before preparing; seller can cancel from placed/accepted/preparing). Unpaid orders TTL-expire after 15 minutes via MongoDB index on expiresAt.
**Deployment:** Frontend on Vercel CDN; 6 APIs on Render Web Services; RabbitMQ rabbitmq:3-management Docker on EC2 t2.micro; MongoDB Atlas M0. Documented capacity: ~50–100 concurrent active users on current tiers; ~150–250 WebSocket connections before Realtime memory pressure.
Key Engineering Decisions
- •Decomposed into six microservices by domain boundary (auth, restaurant, utils, realtime, rider, admin) — each with its own Dockerfile, Render Web Service, and env config. Enables independent deploys and fault isolation; Restaurant can restart without killing WebSocket connections on Realtime.
- •RabbitMQ on AWS EC2 for `payment_event` and `order_ready_queue` instead of synchronous payment→order HTTP chains. Gateway webhooks are async and retry-prone; durable queues ensure Utils acknowledges instantly while Restaurant marks paid, increments coupon usage, and emits `order:new` at its own pace.
- •Designed CouponEngine with Strategy + Factory + Facade + Repository + Validator — two live algorithms (`flat`, `percent_cap`) behind one `apply()` API. Adding BOGO or free-delivery promos means a new strategy class, not a checkout rewrite. Documented with class and sequence diagrams in ARCHITECTURE.md.
- •Mirrored `orderPricing.ts` on frontend checkout — delivery tier, platform fee, small-order surcharge, and coupon discount preview match server totals before `POST /api/order/new`. Eliminates payment-surprise UX bugs.
- •Dedicated Realtime microservice for Socket.IO — decouples long-lived WebSocket connections from stateless Restaurant APIs. Rider GPS flows: rider client → internal emit API → `rider:location` → customer tracking map. JWT verified at handshake; rooms scoped per user and restaurant.
- •Sequential nearest-first rider dispatch with `$geoNear` + 10s timeout per offer — fairer and lower notification noise than broadcast-to-all-riders. Seller can re-trigger dispatch if every rider times out.
- •jsPDF client-side receipt generation — delivered orders export PDF (items, fees, coupon savings, payment ID) in-browser without a document microservice or render queue.
- •Dual payment gateways behind Utils (Razorpay domestic + Stripe international) normalizing to one `PAYMENT_SUCCESS` event — Restaurant consumer stays gateway-agnostic.
- •Per-route `express-rate-limit` tuned from actual configs (10 orders/min, 20 payments/min, 30 coupon validations/min) with internal service bypass — protects MVP infra without throttling RabbitMQ consumers.
- •MongoDB `2dsphere` on restaurants, addresses, and riders — single index strategy powers both customer discovery and rider dispatch proximity in sub-ms aggregation pipelines.
Business / Product Thinking
ByteBites is positioned as a **production-grade systems portfolio product**, not a tutorial clone. Tagline: *Crave it. Order it. Love it.* — the landing page, mobile mockup, and orange brand system signal a real consumer product, while the backend demonstrates senior-level distributed systems thinking.
**Target users for the demo:** recruiters and interviewers evaluating full-stack + system design depth; the VIVA_DOCUMENTATION.md file is structured for technical deep-dives.
**Go-to-market loop:** live app at byte-bites-nine.vercel.app → platform demo video → GitHub with architecture diagrams → interview walkthrough of coupon LLD + RabbitMQ payment flow + rider dispatch.
**Revenue model (implemented in pricing logic):** ₹7 platform fee per order, distance-tiered delivery charges, small-order surcharge, admin-managed coupon campaigns, and rider payout formula — foundation for commission-on-GMV and subscription tiers later.
**Trust & ops signals:** admin verification before sellers/riders go live, user ban enforcement, transparent checkout fee breakdown, JWT + internal service keys, and documented rate limits with honest capacity estimates (~50–100 smooth concurrent users on Render + Atlas M0 + single Realtime node). Upgrade path documented: Redis Socket.IO adapter, Atlas M10+, managed RabbitMQ, k6 load tests.
Results & Impact
Live at byte-bites-nine.vercel.app — fully deployed across Vercel (frontend), Render (6 services), AWS EC2 (RabbitMQ), and MongoDB Atlas.
**Platform scale:** 6 independent microservices · 3 durable RabbitMQ queues · 10+ MongoDB collections with geospatial + TTL indexes · 5 Socket.IO event types · 2 payment gateways · 4 role dashboards · Dockerfiles per service.
**Customer (shipped):** Google OAuth + JWT · geo restaurant discovery (~5 km) · search & category filters · dynamic ETA on explore/cart/tracking · smart single-restaurant cart · Leaflet address picker + Nominatim geocoding · checkout with live coupon validation & fee breakdown · Razorpay (INR/UPI) + Stripe · full order lifecycle tracking · **live rider GPS map** (OSRM route + moving dot via Socket.IO) · order history + reorder · free cancel before preparing · post-delivery restaurant + rider reviews · **PDF receipt download (jsPDF)** · dark/light theme.
**Coupon engine (shipped):** Strategy-pattern discount system with flat + percent_cap algorithms · 5-step validator chain · admin CRUD · per-user + global usage limits · async usage recording post-payment only.
**Seller (shipped):** admin-verified onboarding · menu CRUD + Cloudinary images · item availability toggles · open/close restaurant · real-time order:new feed with sound alerts · kitchen workflow (accept → preparing → ready) · cancel + dispatch retry · 7-day revenue chart, top items, status breakdown.
**Rider (shipped):** admin-verified profiles · online/offline + live GPS · sequential nearest-first dispatch (10s accept window) · pickup → delivered status flow · **live location broadcast to customer** · per-trip earnings · today/week/all-time dashboard · last 30 trips with route snapshots · average rating display.
**Admin (shipped):** user ban/unban · restaurant & rider verification queues · coupon create/edit/toggle/delete · platform GMV, fees collected, 7-day GMV chart · top restaurants by revenue.
**Documentation & assets:** GitHub · Watch Demo · ARCHITECTURE.md (Mermaid diagrams) · VIVA_DOCUMENTATION.md · API reference.
What I'd Do Differently
The shared MongoDB Atlas cluster is pragmatic for MVP but not true database-per-service — I'd split databases or enforce strict connection pools per service before scaling past ~200 concurrent users. Socket.IO needs a Redis adapter and horizontal Realtime replicas before exceeding ~250 concurrent connections. Automated Razorpay/Stripe refund pipelines should replace the current cancel-time refund message. Formal k6/Artillery load tests would replace estimated capacity numbers with measured p95 latency. FCM/APNs push notifications would complement in-app socket alerts for riders. An integration test suite covering payment → RabbitMQ → order:new → dispatch would guard the async critical path in CI.