There is one word in our database that we never use: jazzcash.
It sits there as a legacy value in an old enum, left over from the plan we started with. That dead word shaped our entire final year project.
We wanted to build SmartBite: a marketplace where home chefs cook from their own kitchens and sell to customers nearby. Riders deliver. Ingredient vendors supply the chefs. Admins keep the platform honest.
Every tutorial online says the same thing: plug in a payment gateway and you are done. In Pakistan, that usually means JazzCash. We went a different way and built our own money flow instead.
This is how we built the whole system, and what it taught me.
SmartBite: Homemade Meal Delivery Network — BSCS Final Year Project, Group F25CS010, University of Central Punjab. Advisor: Dr. Rabia Tehseen. Team: Abdullah Maqsood, Huzaifa Iftikhar, Moizz Ahmad. I worked on the mobile apps and the recommendation engine.
THE MONEY PROBLEM
A gateway is not just an API key. It is a merchant account, a registered business, paperwork, and an approval process. A three-student team building a final year project has none of that.
So we dropped the gateway entirely and designed a payment flow around what people here already use every week: their own bank app.
Here is what happens when a customer checks out:
- The screen shows our merchant bank account (IBAN) and a QR code for the exact amount.
- The customer opens their own banking app and sends the money. A normal Raast or bank transfer. The same thing they already do every week.
- The customer uploads proof — a screenshot or the transaction receipt.
- An admin checks the transfer against the real bank account and approves or rejects it.
- Only after approval does the order move forward.
No gateway. No API keys. No monthly fee.
One small decision saved us from a whole class of bugs: we store every amount as an integer in paisa, never as a decimal. Money in floating point is a famous way to lose a rupee here and there and never find it again.
Is manual verification slower than a card payment? Yes. But it works today, in this country, with no company registration. Sometimes the right engineering answer is the one that can actually run.
FIVE APPS, ONE BACKEND
SmartBite is not one program. It is five, each one runnable on its own:
server/
The API everything talks to. Built with Node.js, Express 5, TypeScript, Mongoose (MongoDB), and Socket.IO.
web-dashboard/
Chef, vendor and admin portals. Built with Next.js 15, React 19, and Tailwind CSS.
mobile-app/
Customer and rider app in one project. Built with Expo SDK 54, React Native 0.81, and expo-router.
ai-engine/
Meal recommendations. Built with Python 3.11, FastAPI, and scikit-learn.
landing/
Public website. Built with Next.js 15 and Tailwind CSS.
The two frontends share one backend and one users collection. So an account made on the web signs in on mobile. That sounds obvious. It is the kind of obvious thing that breaks quietly if you do not plan it on day one.
The customer app and the rider app live inside one Expo project, as two route groups. Two experiences, one codebase, one build to maintain. For a three-person team, that decision paid for itself many times.
THE AI ENGINE CAN DIE AND NOBODY NOTICES
Our recommendation service is a separate Python process. That worried me. A separate service is a separate thing that can fall over at 2 a.m. during the demo.
So we made it optional.
The backend asks the AI engine for recommendations. If the AI engine does not answer, the backend quietly falls back to a popularity ranking and the app keeps working. The customer sees meals either way. Nothing breaks. Nobody sees an error.
We did the same thing with maps. Google Maps is integrated on the server, with a plain straight-line distance fallback built in. The entire system runs with no paid API keys. For a student project that has to work on a demo laptop in a viva room with bad internet, this mattered more than any feature.
If I could teach one idea from this project to a younger student, it is this: every external thing you depend on should have a boring backup. Build the backup first. Then you can sleep.
HOW THE RECOMMENDATIONS ACTUALLY WORK
There are two halves.
The live half runs inside the app:
Every meal is turned into a text document (name, description, tags) and compared using TF-IDF with cosine similarity. If you ordered biryani, you get things that look like biryani in word-space.
Meals nobody has ordered yet cannot be compared to your history, so they are ranked by popularity, using a Bayesian average, not a raw star rating. This matters. One 5-star review from the chef's cousin should not beat 4.6 stars from forty real customers. The Bayesian prior pulls small samples toward the global average until they earn their score.
Every recommendation carries a reason in plain words: "Similar to meals you ordered recently", "Popular dish (4.6/5 from 12 reviews)", or "New on SmartBite."
That last part was not in the requirements. I added it because a recommendation you cannot explain is a recommendation nobody trusts.
The offline half is a proper collaborative-filtering model. We trained an SVD model on the public Food.com dataset from Kaggle (1.1M+ ratings, 230K+ recipes), filtered down to 150,000 interactions:
120,000 for training
30,000 for testing
14,518 users
14,972 recipes
100 factors
20 epochs
Results on the held-out test set:
RMSE: 0.936
MAE: 0.536
Precision@10: 0.913 (relevance threshold 4.0)
The honest bit: a brand-new marketplace has almost no rating history of its own. Collaborative filtering needs a crowd. So the live system leans on content similarity and popularity, and the trained model proves the method works and is ready for when there is real data.
Writing that in the report felt like admitting weakness. It is not. It is knowing which tool works at which stage.
DELIVERY: THE PART THAT HAS TO WORK IN REAL TIME
This is the chain, and we tested every link of it with live requests against a running server:
- The chef marks an order ready for pickup.
- The dispatcher computes and sends offers to nearby riders.
- A rider accepts. The order becomes out for delivery and the rider is attached to it.
- The rider's phone sends its GPS position to the server as they move.
- The customer's app asks for the order every 15 seconds and gets back the order status, the chef's kitchen location, and the rider's latest position.
- The pin on the customer's map moves.
- Delivered.
One bug from that testing is my favourite thing in the whole project.
The rider's active delivery screen did not refresh. When a chef or admin changed the order status, the rider saw nothing until they pulled down to refresh manually. Everything on the server was correct. The data was right. The rider just never saw it.
We found it by walking the flow like a real user instead of reading the code.
A system can be completely correct and still be broken for the person using it. No test we had written would have caught that.
WHAT I WOULD TELL A STUDENT STARTING THEIR FYP
Choose constraints, then design. We could not have a payment gateway. That was not a limitation to complain about; it was the most interesting design problem in the project.
Make every dependency optional. AI engine down, no maps key, no internet — it should still run.
Build the demo path first. Seed data, demo logins, one script that starts everything. You will run it a hundred times.
Test like a user, not like a programmer. Click through the whole flow on a real phone. That is where the real bugs live.
Store money as integers. Always.
Write down why. Six months later, in the viva, "why did you choose this?" is the question you get asked. The answer should already be written down.
We shipped it: five applications, one backend, live delivery tracking, a working payment flow with no gateway, and a recommendation engine that explains itself.
And the thing that made it good was not the AI. It was the boring decisions.
Integer paisa. Fallbacks everywhere. One account across two apps. A backup for every dependency.
The clever part gets you marks. The boring parts get you a system that still runs on demo day.
Huzaifa Iftikhar is a software engineer in Lahore, Pakistan. SmartBite was his BSCS final year project at the University of Central Punjab.
Top comments (0)