01 / 09
Final Project — Full Stack Development

Audiophile
Nigeria's Premium Audio Store

A production-ready e-commerce platform built on the MERN stack with TypeScript — designed specifically for the Nigerian consumer audio market.

MongoDB Express.js React 18 Node.js TypeScript Cloudinary JWT Auth
Scroll to explore
The Problem
Market Gap Identified

Nigeria's audio market is growing fast.
Nobody is serving it properly online.

₦2.1T
Electronics market size
Nigeria's consumer electronics market valuation — one of Africa's largest, growing annually at 11.4%
67M+
Internet users
Nigeria has the highest internet user count in Africa — a massive digital-native buying audience
73%
Mobile-first shoppers
Of Nigerian online shoppers browse and buy primarily on mobile devices — demanding responsive design
0
Dedicated premium audio stores
No Nigerian-built, responsive, full-stack e-commerce platform exists specifically for premium audio gear
Market Fit
Why Nigeria? Why Now?

Five converging forces make this the right market, right now.

1

The Afrobeats & Podcast Boom

Nigeria exports more music content than any other African nation. Creators, engineers, and everyday consumers are investing heavily in audio quality — headphones, studio monitors, and wireless earphones are aspirational purchases.

2

Rising Middle-Class Disposable Income

Nigeria's expanding urban middle class (est. 11M households) are actively seeking premium goods. Products priced ₦150,000–₦750,000 are attainable for this demographic and signal status.

3

E-commerce Infrastructure Maturing

Opay, Flutterwave, Paystack and bank transfers have normalised online payments. Nigerians are comfortable buying high-value goods digitally.

4

Work-From-Home & Remote Culture

Post-2020 hybrid work culture has permanently increased demand for quality headsets, speakers, and earphones for calls, content, and music.

5

Gen Z Digital Natives Are Buying

Nigeria's 18–34 age group (the largest demographic) are brand-conscious, quality-aware, and prefer curated online shopping experiences over the chaos of open markets.

The Solution
What We Built

A complete, production-grade
audio e-commerce platform

🛒

Full Shopping Experience

Product browsing, detailed pages, cart management, and a validated checkout flow with e-Money and cash on delivery options.

🔐

Secure Authentication

JWT-based registration and login, protected routes, user profile management, Cloudinary avatar uploads, and order history.

⚙️

Admin Dashboard

Full product CRUD, order status management, user role control, revenue analytics, and a monthly revenue chart — all behind protected admin routes.

📱

Mobile-First Design

Responsive across all screen sizes — mobile (375px), tablet (768px), desktop (1024px+) — 1366px and 1440px screens are pixel-identical.

☁️

Cloud Image Storage

All product and user images served from Cloudinary CDN for fast loading globally — optimised for Nigerian broadband conditions.

Performance-Optimised

Lazy-loaded pages, code splitting, localStorage cart persistence, and a custom 404 page — built to Vercel deployment standards.

Architecture
Technical Architecture

Industry-standard stack, zero shortcuts.

Frontend — Client

React 18 TypeScript Vite Tailwind CSS React Router v6 Axios Context API Lazy Loading React Hot Toast

Backend — Server

Node.js Express.js TypeScript MongoDB Atlas Mongoose JWT bcryptjs Multer CORS

Cloud & DevOps

Cloudinary CDN Vercel (Client) Render (Server) MongoDB Atlas Git / GitHub

Design & UX

Manrope Typeface Mobile-First Custom 404 SPA Routing Toast Notifications
Browser Vercel CDN React App (Vite) Axios + JWT Render Server Express API MongoDB Atlas
Image uploads: Express + Multer Cloudinary CDN URL stored in MongoDB
User Access Levels
Role-Based Access Control

Three distinct user experiences, one platform.

👤

Guest Visitor

No account required

  • ✅ Browse all products
  • ✅ View product details
  • ✅ Add to cart
  • ✅ Checkout as guest
  • ❌ Order history
  • ❌ Save profile details
  • ❌ Avatar & settings
RECOMMENDED
🔐

Registered User

Create a free account

  • ✅ Everything guests can do
  • ✅ Orders linked to account
  • ✅ View order history
  • ✅ Profile settings
  • ✅ Upload avatar photo
  • ✅ Pre-filled checkout
  • ❌ Admin controls
👑

Store Admin

Owner / operator access

  • ✅ Everything above
  • ✅ Dashboard + analytics
  • ✅ Add / edit / delete products
  • ✅ Upload product images
  • ✅ Update order statuses
  • ✅ View all orders
  • ✅ Manage user accounts
Business Model
Commercial Viability

This is not just a project.
It is a launchable business.

Revenue Scenario — Year 1

If just 2 units/day are sold at an average price of ₦180,000, the platform generates ₦131.4M annually — a viable SME income before scaling.

₦131M+
Projected Year 1 Revenue

Revenue Streams

  • 📦 Direct product sales
  • 🤝 Brand partnerships (Sony, JBL, Sennheiser)
  • 🏪 Marketplace model (third-party sellers)
  • 🛡️ Extended warranty upsells
  • 📣 Sponsored product placement

Competitive Advantages

  • 🎯 Category-focused (not generic)
  • ⚡ Faster load times than Jumia
  • 💳 Cash on Delivery supported
  • 📱 Truly mobile-optimised UI
  • 🛠️ Admin controls — no dev needed
Development Journey
Challenges & What We Learned

Real problems. Real solutions.

Challenge 1

TypeScript type safety across the stack

Keeping client-side and server-side types in sync across Mongoose models, API responses, and React components required careful interface design.

✓ Solution: Shared interface naming conventions + explicit response typing on Axios calls

Challenge 2

JWT auth across page refreshes

Ensuring the user stays logged in after a browser refresh — without flashing a login redirect — required careful localStorage hydration before rendering protected routes.

✓ Solution: AuthContext loading state blocks rendering until localStorage is checked

Challenge 3

Vercel SPA 404 routing

React Router routes like /headphones work in the browser but Vercel returns a 404 when someone refreshes on that URL — a common SPA deployment pitfall.

✓ Solution: vercel.json rewrite rule sends all paths to index.html, preserving our custom 404

Challenge 4

Cloudinary image upload pipeline

Multer stores files in memory as Buffers, but Cloudinary SDK expects a file path or base64 string — bridging this without writing to disk was non-trivial.

✓ Solution: Convert Buffer to base64 data URI in-memory before passing to Cloudinary SDK
Key learnings: RBAC patterns REST API design Mongoose aggregation Lazy loading CDN integration Deployment pipelines
Judge Q&A Preparation
Likely Judge Questions

Be ready for anything.

Click each question to reveal the model answer.

Why did you choose the MERN stack specifically for this project?
The MERN stack (MongoDB, Express, React, Node.js) uses JavaScript/TypeScript across the entire application — one language from database to browser. This reduces cognitive overhead, allows code reuse for types and interfaces, and has a massive ecosystem of packages. MongoDB's document model maps naturally to product catalogs with varying attributes. React's component model suits a design-heavy e-commerce UI. And Node.js handles concurrent API requests well for a shopping platform. It is also one of the most in-demand stacks in the Nigerian tech job market right now.
How does your application handle security — specifically authentication?
We implement JWT (JSON Web Tokens) for stateless authentication. When a user logs in, the server signs a token with a secret key using HS256 algorithm and returns it. The client stores this token in localStorage and sends it in every subsequent request as a "Bearer" header. On the server, our "protect" middleware verifies the token signature before allowing access to any protected endpoint. Passwords are never stored in plain text — we use bcryptjs with a salt factor of 10 to hash all passwords before saving to MongoDB. Admin routes have a second middleware layer that checks the user's isAdmin flag.
Why TypeScript over plain JavaScript? What value did it add?
TypeScript adds static type checking at compile time — catching bugs before they reach production. For example, if our API returns a product with a "price" field but our React component tries to use "cost", TypeScript throws an error immediately rather than a silent bug at runtime. We defined shared interfaces for all our data shapes — IUser, IProduct, IOrder — which enforces consistency between our Mongoose models and our React components. TypeScript also makes the codebase self-documenting: a new team member can understand exactly what data a function expects just by reading its signature. Every TypeScript-specific line in our codebase has an inline comment explaining it — making it pedagogically clear for students learning TypeScript for the first time.
How does your app perform on slow Nigerian internet connections?
We addressed this in several ways. First, all images are served from Cloudinary's global CDN which has edge nodes closer to African users, dramatically reducing image load times compared to serving from a UK or US server. Second, we use React's lazy() and Suspense to split the JavaScript bundle — instead of loading all 9 pages at once, only the page the user is on gets loaded. This cuts the initial bundle size significantly. Third, all product images use loading="lazy" so off-screen images don't block the initial render. Fourth, the shopping cart is persisted in localStorage so users don't lose their cart if their connection drops. These optimizations make the app viable on 3G connections.
What makes this different from just using Shopify or WooCommerce?
Shopify and WooCommerce are excellent platforms but they have significant limitations for the Nigerian market and for our learning objectives. First, Shopify charges monthly fees of $29–$299 USD plus transaction fees — that's ₦45,000–₦460,000 monthly just for the platform, before hosting costs. Building custom means no recurring platform fees. Second, customisation is constrained on Shopify — you cannot change the checkout architecture or add custom backend logic without expensive apps. Our platform is 100% ours to extend. Third, and most importantly for this project: building from scratch demonstrates that we understand every layer of a web application — from database schema design to JWT middleware to React state management — which a hosted solution completely hides.
How would you scale this if you had 10,000 users hitting it simultaneously?
Several scaling strategies would be needed. At the database level: MongoDB Atlas supports horizontal sharding and read replicas — we'd enable read replicas so database reads (browsing products) don't compete with writes (placing orders). At the server level: we'd move from a single Render instance to a load-balanced cluster behind Nginx. We'd introduce Redis for caching frequently-accessed data like the product catalogue — most users view the same 6 products, so caching API responses reduces database load by ~80%. We'd add a message queue (like Bull with Redis) for order processing so a traffic spike doesn't cause timeout errors. The frontend on Vercel already scales infinitely since it's a static CDN — that's not a bottleneck. We'd also implement rate limiting on the API to prevent abuse.
What would you add if you had 3 more months?
The most impactful additions for the Nigerian market would be: (1) Paystack integration — Nigeria's leading payment gateway — to enable direct card payments, bank transfers, and USSD payments without leaving the site. Currently we support Cash on Delivery and e-Money which are placeholders. (2) Product search with full-text search and filters by price range and category. (3) Product reviews and star ratings — social proof is critical for high-value purchases online. (4) SMS order notifications via Termii or Twilio Africa — Nigerians respond better to SMS than email. (5) A wishlist/save for later feature. (6) Inventory management — track stock levels and automatically show "Out of Stock" badges. (7) Progressive Web App (PWA) capabilities so users can install it on their phone home screen.
Explain how Context API works in your project and why you chose it over Redux.
React's Context API is a built-in solution for sharing state across components without prop drilling (passing data through many layers of components). We have two contexts: AuthContext manages the logged-in user state — any component can call useAuth() to get the current user, log in, or log out without needing to pass those functions down through props. StoreContext manages the shopping cart and product data globally. We chose Context API over Redux because our state requirements are straightforward — we have two bounded domains (auth and cart) with simple operations. Redux adds significant boilerplate (actions, reducers, selectors, middleware) that would be over-engineering for this scale. Context API, combined with useState and useEffect hooks, provides everything we need with far less code and complexity. If the app grew to 50+ components with complex shared state and frequent updates, Redux Toolkit would become worth the trade-off.
What is the role of Cloudinary in your project — couldn't you just store images in MongoDB?
MongoDB is a document database optimised for structured data — storing binary image files in it as Base64 strings would massively bloat the database, slow down every query, and make the data hard to back up. MongoDB has a 16MB document size limit which a single high-res product image could approach. Cloudinary is purpose-built for media — it stores images on a global CDN, automatically compresses and optimises them, and serves them from the edge node nearest to the user. It also provides free image transformations: you can request a 200x200 thumbnail of a 4K image by changing the URL parameters, without storing multiple versions. In our architecture, we upload the image file to Cloudinary and store only the returned URL string in MongoDB — giving us the best of both worlds.
How does your admin dashboard prevent unauthorised access?
Access is protected at two independent layers. On the frontend: the AdminRoute component checks the AuthContext for a user with isAdmin: true before rendering any admin page — non-admins are redirected to the homepage. However, frontend checks alone are never enough security. On the backend: every single admin API endpoint (/api/admin/*) runs through two middleware functions in sequence — first "protect" which verifies the JWT token and loads the user from the database, then "admin" which checks user.isAdmin === true. Even if someone bypassed the frontend check (by directly calling our API with curl or Postman), the server would still return a 403 Forbidden response. This double-layer approach — client guard plus server guard — is the industry standard for RBAC (Role-Based Access Control).

🎧

Audiophile Nigeria

Built with industry-standard tools. Designed for the Nigerian market. Ready for production.

Thank you — we welcome your questions