Mahesh Kumar Muddunuru
Illustration of Mahesh in an apron holding a steaming tiffin carrier.
Dakshin FoodsClient work · dakshinfoods.ca

A family kitchen was paying for software that couldn't run its business.

Dakshin Foods is a South Indian kitchen in New Westminster, BC. Most of its business is tiffin meal plans delivered every weekday. I built the system that runs it, from sign-up to the photo at the customer's door.

one real kitchen, and its whole day
Role
Designed, built, maintain
Client
Dakshin Foods, New Westminster
Status
Live since July 2026
Stack
Next.js · Supabase · Flutter · Clover
Replacing
A paid ordering platform
Where it started

The meal plans lived everywhere except in the software.

The ordering site they paid for handled takeout and nothing else. Meal plans lived in a notebook and a WhatsApp thread, renewals were chased by hand, and drivers got addresses by text, one at a time. Before writing any code I sat through how a morning actually goes, and each thing the owner did by hand became a screen.

Before
  • Meal plans in a notebook and WhatsApp
  • e-Transfers matched to people by hand
  • Addresses texted to drivers one by one
  • Till sales and meal plans never added up
Now
  • Customers enrol, pay and skip days online
  • A cook sheet and box labels ready each morning
  • A driver app with stops in order and a photo at each door
  • Till, web and meal-plan sales in one report
What I built

Plans, the kitchen and the money in one place.

Customers enter a postal code, which sets their area and delivery fee, then pay by card through Clover or by e-Transfer. From the portal they can skip a day before 11 p.m., pause, rate a delivery, or renew onto a different plan.

Every night at 3 a.m. the next day's boxes are generated. The kitchen gets a cook sheet, box labels with the stop number and allergy notes, and a dispatch board. The Clover till syncs nightly, so walk-ins, online orders and meal plans finally add up in one report.

On the road

A driver app, and a photo instead of a phone call.

Drivers use a Flutter app from the App Store. Each stop shows its number (“Stop 4 of 27”), allergies and a photo of the customer's gate. A proof photo is required at every door, and customers who have opted in get it on WhatsApp.

Drivers can't read the customer tables at all. Each stop carries a copy of only what that delivery needs, and I test those rules from outside the database, signed in as each role.

Things that broke, and what I did

Four problems a real kitchen found.

01

A pin 4.5 km from the door

The owner glanced at the delivery map and said, “That’s not where this customer lives.” The pin was 4.5 km away, and had been for two weeks.

WhyThe backup geocoder matched the street and quietly dropped the house number. The wrong pin was cached, so the better provider was never asked again.

The fixNo pin beats a wrong pin. The house number has to match, addresses are looked up fresh on every run, and each pin is cross-checked against a second provider. A sweep of the other addresses turned up six more that were off or missing.

02

$6.99 on the board, $9.99 at the till

For a month, the TV menu board and the printed menu showed one dish at $6.99. The till rang it up at $9.99.

WhyThe menu lived in five places: the till, the database, the website, the QR page and the board generator. All of them were updated by hand.

The fixThe till is now the only place a price lives. Everything else is generated from it, and the build refuses to run if a price appears anywhere else.

03

An export that only listed the changes

One customer’s row in the old platform’s export said “roti (4pc)”. Their actual box was dal, sabzi and four roti.

WhyThe export only listed what each customer had changed, not what was in the box. Importing it as it was would have sent people a third of their dinner, and nothing would have complained.

The fixI read every box from the old portal by hand, then checked each row after the database triggers ran. That caught end dates the triggers had quietly rewritten on the way in.

04

A timeout that looked like a decline

Caught in review, before it reached anyone: the payment code couldn’t tell a timeout from a declined card.

WhyIf the bank charged the card but the reply got lost, the page would say “declined” and invite the customer to pay again.

The fixA charge now has three outcomes: paid, declined or unknown. Unknown locks the link and tells the customer not to re-enter their card, a job checks with Clover every five minutes, and one database view lists any money we can’t account for. It should always be empty.

Where it is now

The owner runs it every day.

Enrolments, the cook sheet, dispatch, renewals and refunds all happen in the platform now, and customers are moving off the old ordering platform one delivery route at a time. When the day changes, the software gets a new screen.

Other kitchens turned out to have the same problems, which is how Tiffinware started.

Running a business on spreadsheets and group chats?

This is the work I like most: watch how the day actually goes, then build the system around it.

Tell me about it