Logo

Command Palette

Search for a command to run...

Command Palette

Search for a command to run...

Writing
PreviousNext

Building Samvad: A Service Booking App from Scratch

A case study on building Samvad end to end — a Flutter and Appwrite service booking app where professionals list their availability and customers book, chat, and pay. The story behind the stack choices, the realtime chat, and the night Razorpay taught me about reconciliation.

Some projects come from a job post. This one came from a look across a table.

I was deep in my yearly theme project at college, and my guide had asked me to build Jal Kalash Seva — an online seva and devotion platform. I remember the demo day for it more than I remember the grade. He watched me click through the thing I had built, asked a few sharp questions, and then went quiet for a second. Then he said the sentence that turned a class assignment into a real client relationship:

"Can you build something like this for me?"

There is a specific weight to that question when it comes from a mentor. A stranger hiring you is a transaction. Someone who has watched you struggle through a semester hiring you is a vote. I did not want to let that vote down. That something became Samvad, and I built it end to end, alone.

What Samvad is

Samvad connects professionals with the people who need them — doctors, lawyers, consultants, educators, anyone who sells their time in slots.

A professional signs up, builds a portfolio the way you would on LinkedIn — banner, headline, skills, years of experience, past work — and sets their weekly availability. A customer browses by category and city, opens a profile, finds an open slot, and books it. From there the two of them can message each other, and the professional confirms, declines, completes, or cancels.

It is a two-sided marketplace, and I learned the hard way that those are quietly brutal. Every screen exists twice — once for the person offering the service, once for the person buying it — and the two halves have to agree at every moment. A slot the professional just blocked cannot still look bookable to a customer three taps deep into checkout. Most of the difficulty in Samvad was not any single feature. It was keeping two people's realities in sync.

Choosing the stack

I picked Flutter for the app and Appwrite for the backend, and I can defend both choices at 2am.

Flutter, because the developer experience is genuinely joyful. One codebase, hot reload that keeps you in flow, and a widget model that let me build two entirely different dashboards — customer and professional — without maintaining two apps. I used Riverpod for state and go_router for navigation, so the same binary boots into two different worlds depending on who signs in. Login as a customer and you get browse-and-book. Login as a professional and the whole app rearranges itself around your calendar.

Appwrite, because I had already shipped two products on it — Shagnest and Purbasha — so its auth, database, storage, and realtime were muscle memory by then. But the deeper reason was ownership. Appwrite self-hosts cleanly on a VPS, and for a client who is going to run this himself, "you own the server and the data, forever" is a far better thing to hand over than "you rent it from a platform until they change their pricing." I wanted to give him something that was actually his.

The realtime chat

The part I sank the most nights into was the chat.

Anyone can build a chat that works in a two-message demo. Building one that stays smooth as conversations grow, with messages arriving live and the list not fighting the scroll position, is a different animal. I leaned on Appwrite's realtime subscriptions so messages push to the client instead of the client nervously polling every few seconds. And I structured the message data so opening a thread loads a recent window instantly instead of dragging the entire history up from the database every single time.

Then I added voice messages, because a booking conversation is often faster spoken than typed — record, upload, play back inline, using record for capture and just_audio for playback. Voice notes sound trivial until you are actually holding the whole lifecycle in your hands: the recording that has to stop cleanly, the upload to storage that cannot freeze the UI, the playback that has to start the instant a thumb hits play. I rebuilt that flow more times than I would like to admit before it finally felt instant instead of almost instant.

Bookings that do not collide

The scariest bug in any booking app is the one you cannot see in testing: two people grabbing the same slot in the same second.

You will never catch it clicking around by yourself. But launch to real humans and eventually two customers will tap "confirm" on the same 3pm Tuesday a half-second apart, and if you trusted the client to check availability, you now have one furious professional double-booked and two customers who both think they won. So I moved the check to where it cannot be raced — a server-side Appwrite function that validates the booking at the moment of creation, checking overlaps against the professional's existing bookings before the record is even allowed to exist. Two simultaneous grabs resolve to exactly one winner. It is invisible when it works, and that is the whole point.

The night Razorpay taught me about reconciliation

Payments were where I got humbled.

I thought integrating Razorpay would be "add the SDK, launch checkout, done." It is not. The real lesson hides in one ugly truth: the payment succeeding and your database recording it are two separate events, and they can drift apart. The user's money can leave their account while the callback that was supposed to tell your app about it quietly gets lost — a killed process, a flaky network, a backgrounded app.

I found this the way you always find it: a test payment went through on Razorpay's dashboard, but Samvad acted like nothing happened. For a bad few minutes I was staring at real money in one system and no record of it in mine, imagining that same thing happening to my guide's actual customer. That fear is what forced the fix — treating the payment and the booking state as two things that must be reconciled, not assumed to agree. It is the least glamorous code in the whole app and easily the most important.

Where it is now

Development is done. I have handed the entire codebase over to my guide, and it is in testing now while he builds a marketing campaign for the launch. It is not public yet, so I am not going to quote user numbers I do not have — but the build is complete, every flow works end to end, and it is fully his to take to market.

What I took from it

The technical scars are real — realtime chat, race-safe bookings, payment reconciliation — but the thing I actually carry from Samvad is quieter. This project never appeared on a job board. It came from someone watching how I handled a smaller thing and deciding that was enough to trust me with a bigger one.

That is the kind of work I want more of. Build something well, do right by the person who hired you, and let the next project come from the one who saw it up close.