<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: ALISAM SRIVARDHAN</title>
    <description>The latest articles on DEV Community by ALISAM SRIVARDHAN (@alisam_srivardhan_cbaa623).</description>
    <link>https://dev.to/alisam_srivardhan_cbaa623</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4081917%2F11bd2be9-b974-4d88-a58d-3dbfab168445.jpg</url>
      <title>DEV Community: ALISAM SRIVARDHAN</title>
      <link>https://dev.to/alisam_srivardhan_cbaa623</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/alisam_srivardhan_cbaa623"/>
    <language>en</language>
    <item>
      <title>Building TravelMate: Part 2 — Architecture Decisions (And the Ones I Almost Got Wrong)</title>
      <dc:creator>ALISAM SRIVARDHAN</dc:creator>
      <pubDate>Sun, 06 Sep 2026 04:59:59 +0000</pubDate>
      <link>https://dev.to/alisam_srivardhan_cbaa623/building-travelmate-part-2-architecture-decisions-and-the-ones-i-almost-got-wrong-3o0a</link>
      <guid>https://dev.to/alisam_srivardhan_cbaa623/building-travelmate-part-2-architecture-decisions-and-the-ones-i-almost-got-wrong-3o0a</guid>
      <description>&lt;p&gt;This is Part 2 of a 4-part series on building TravelMate. Part 1 covered the idea and the problem. Part 3 dives into the hardest engineering problems — a greedy settlement algorithm, real-time chat security, and an AI integration with actual guardrails. Part 4 comes after the project ships.&lt;/p&gt;

&lt;h2&gt;
  
  
  The rule I set before writing any code
&lt;/h2&gt;

&lt;p&gt;After LexAssist, I made myself sit with the architecture before touching a controller. That felt slow at the time — genuinely, embarrassingly slow, watching classmates already pushing feature commits while I was still drawing entity relationships on paper. But almost every phase since has built cleanly on top of the last one, and I think that's a direct result of the time spent up front, not in spite of skipping it.&lt;/p&gt;

&lt;p&gt;Here's what that architecture actually looks like, and — more usefully — where I almost got it wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  Modular monolith, not microservices
&lt;/h2&gt;

&lt;p&gt;The instinct, especially after reading enough "how big tech does it" blog posts, is to reach for microservices. I didn't. TravelMate is a modular monolith — one deployable application, but organized internally into clean, independent modules (auth, trips, matching, chat, expenses, and so on), each with its own routes, controllers, services, and models.&lt;/p&gt;

&lt;p&gt;The honest reason: microservices solve problems I don't have. I don't have multiple teams stepping on each other's code. I don't have one module that needs to scale independently at 100x the traffic of another. What microservices would have given me, at this stage, is network calls between services, more infrastructure to deploy and monitor, and distributed-systems bugs I'd have zero practice debugging. A modular monolith gives almost all the organizational benefit — clear boundaries, one module's mess doesn't leak into another's — without any of that cost. If a module like matching or chat ever needs to scale independently, the boundaries are already clean enough to extract it later. That's the actual argument for "modular" in modular monolith: it's monolith now, extractable later, by design.&lt;/p&gt;

&lt;h2&gt;
  
  
  The decision I made over and over: embed or reference?
&lt;/h2&gt;

&lt;p&gt;If there's one architectural question I answered more times than any other, it's this one. MongoDB lets you either embed related data directly inside a document, or store it separately and reference it by ID. Get this wrong in enough places and your database becomes either a tangle of oversized documents or a maze of unnecessary joins.&lt;/p&gt;

&lt;p&gt;The rule I settled on, and reused constantly:** embed when the data is small, bounded, and always fetched together with its parent. Reference when it's unbounded, needs independent querying, or shared across multiple parents.&lt;br&gt;
**&lt;br&gt;
A user's profile and travel preferences? Embedded — small, fixed set of fields, always needed alongside the user. Chat messages? Referenced — a trip could accumulate thousands of them, and you need to paginate and query them independently of the trip itself. Expense split participants, on the other hand, look like they should be referenced (money data feels like it should live in its own collection), but they're actually a good embedding case — bounded by trip size, always created and read together with their parent expense. Noticing that distinction — that the right answer follows from the actual access pattern, not from "this is financial data so it must be relational-feeling" — was one of those small realizations that made a lot of later decisions faster.&lt;/p&gt;

&lt;h2&gt;
  
  
  The pattern I didn't expect to reuse eight times
&lt;/h2&gt;

&lt;p&gt;Early on, I needed to stop users from sending duplicate join requests to the same trip. The naive fix — check if a request already exists, then create one if it doesn't — has a real bug hiding in it: two nearly-simultaneous requests can both pass the "does this exist" check before either one finishes writing. Both succeed. Now there are two.&lt;/p&gt;

&lt;p&gt;The fix was a compound unique index at the database level: trip and user together must be unique. Not a check in my code — a guarantee enforced by MongoDB itself, regardless of timing.&lt;/p&gt;

&lt;p&gt;I expected to use that pattern once. I ended up using it for join requests, trip membership, poll votes, reviews, budgets, blocks, community memberships, and trusted-contact shares. Eight different features, the same underlying shape: "at most one of this relationship between these two things, guaranteed even under concurrent requests." By the sixth or seventh time, I stopped re-deriving the solution and just recognized the shape immediately. That's what a good architectural decision actually buys you — not that you solve a problem once, but that you stop having to re-solve it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where I almost got it wrong: trip capacity
&lt;/h2&gt;

&lt;p&gt;The join-request duplicate problem has a sibling that's actually more dangerous: what happens when a trip has one seat left, and two people request to join at almost the same instant? A naive "check seats, then increment" has the exact same race condition, except here the consequence is a genuinely overbooked trip, not just a duplicate row.&lt;/p&gt;

&lt;p&gt;The fix looks almost too simple for how much it matters: the seat-availability check and the increment happen as a single atomic database operation — findOneAndUpdate with the "is there room" condition built directly into the query, not checked separately beforehand. MongoDB guarantees no other operation can slip in between the check and the write. If two requests land at the same moment, the database still processes them one at a time internally, and the second one correctly sees the already-updated count and fails.&lt;/p&gt;

&lt;p&gt;I don't think I would have caught this if I'd been moving fast. It's the kind of bug that works perfectly in every manual test you run — you're one person, clicking one button at a time — and only breaks under conditions you didn't simulate. Slowing down to actually think through "what happens if two people do this at once" before writing the code, rather than after a bug report, is the single habit from this project I'm most likely to carry into everything I build afterward.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;p&gt;Part 3 is where the more interesting problems live: a greedy algorithm for settling group expenses in the minimum number of transactions (with an actual proof for why it's optimal, not just "it seemed to work"), a Min-Heap reused for two completely different purposes, and the real security work behind making sure a Socket.IO chat room can't be joined by someone who was never invited. I'll also walk through integrating an AI trip planner and being deliberate about the difference between a feature that sounds smart and one that's actually guarded against making things up.&lt;/p&gt;




&lt;p&gt;Next: Part 3 — The hardest engineering problems: a provably-optimal settlement algorithm, real-time security, and AI with guardrails.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>buildinpublic</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Building TravelMate: Part 1 — Why I Built a Social Travel Platform (And Why My Last Project Failed)</title>
      <dc:creator>ALISAM SRIVARDHAN</dc:creator>
      <pubDate>Sun, 30 Aug 2026 23:52:49 +0000</pubDate>
      <link>https://dev.to/alisam_srivardhan_cbaa623/building-travelmate-part-1-why-i-built-a-social-travel-platform-and-why-my-last-project-failed-121e</link>
      <guid>https://dev.to/alisam_srivardhan_cbaa623/building-travelmate-part-1-why-i-built-a-social-travel-platform-and-why-my-last-project-failed-121e</guid>
      <description>&lt;p&gt;This is Part 1 of a 4-part series documenting the build of TravelMate, my 3rd-year engineering project. Part 2 covers architecture and tech decisions, Part 3 dives into the hardest engineering problems I solved, and Part 4 (coming after the project ships) covers what I learned.&lt;/p&gt;

&lt;h2&gt;
  
  
  The project that didn't make it
&lt;/h2&gt;

&lt;p&gt;Last year, in my 2nd year, I tried to build something called LexAssist. I don't talk about it much, because it didn't really go anywhere — not because the idea was bad, but because I made almost every mistake a student developer can make on a solo project. I added features before the core worked. I didn't think through the architecture before writing code. Security was an afterthought I kept meaning to "add later." By the time the project deadline arrived, I had a folder full of half-working pieces and no coherent story to tell about any of it.&lt;/p&gt;

&lt;p&gt;It wasn't a fun feeling, explaining in a viva why half the features were "still in progress."&lt;/p&gt;

&lt;p&gt;So when it came time to pick my 3rd-year project, I made myself one promise before I wrote a single line of code: &lt;strong&gt;a complete, working, secure application beats a huge, half-built one, every single time.&lt;/strong&gt; That sentence became the actual first line of my project brief, and I've tried to hold myself to it through every phase since.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem I actually wanted to solve
&lt;/h2&gt;

&lt;p&gt;I travel occasionally with friends, and every time a trip comes together, the same mess happens. Someone starts a WhatsApp group. Someone else makes a spreadsheet for expenses that nobody updates. The itinerary lives in a Google Doc that three people have different edit access to. And before any of that — the actual hardest part — is just &lt;em&gt;finding people who want to go to the same place, at the same time, with a similar budget and vibe.&lt;br&gt;
_&lt;br&gt;
That last part is the real problem. Booking a hotel or a train ticket is a solved problem — a dozen apps do it well. But _finding your people&lt;/em&gt; — other travelers who want roughly what you want, and then actually coordinating with them safely — isn't something any single app handles well. You end up stitching together a search, a group chat, a spreadsheet, and a prayer.&lt;/p&gt;

&lt;p&gt;That's the gap TravelMate is trying to fill:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"Find people who want to take a similar trip, and help them safely form, plan, coordinate, and manage that trip together."&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Not a booking engine. Not another generic social app. A platform built specifically around one core idea: compatibility-based travel group formation.&lt;/p&gt;

&lt;h2&gt;
  
  
  What that actually looks like
&lt;/h2&gt;

&lt;p&gt;Imagine you type in: Goa, from Hyderabad, December 20–24, budget ₹8,000, interested in adventure and beaches, prefer trains.&lt;/p&gt;

&lt;p&gt;Instead of just showing you hotel listings, TravelMate should:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Find existing trips that match what you're looking for&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Find other travelers with similar plans and preferences&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Calculate how compatible you actually are with a given trip or group&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Let you request to join, and help the group form&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Once you're in, give your group a private space to plan everything together — chat, a shared itinerary, polls for decisions, and expense splitting&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That whole loop — discovery, matching, group formation, collaborative planning, safety, and post-trip memories — is the actual product. Not a single feature, but the connective tissue between all of them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this needed to be more than a CRUD app
&lt;/h2&gt;

&lt;p&gt;It would have been easy to scope this down into "a place to post trip listings" — basically a bulletin board. That's a weekend project, not a 3rd-year flagship. I wanted this project to actually demonstrate real software engineering: a genuine compatibility-scoring algorithm (not just filters), real-time features that need actual security thinking (chat rooms that can't leak into each other), concurrency problems that are real distributed-systems concepts wearing a travel-app costume (what happens when two people grab the last seat on a trip at the same instant?), and — because the whole point of "find people to travel with" involves meeting people you don't know well — a genuine safety layer, not a bolted-on afterthought.&lt;/p&gt;

&lt;p&gt;That's also why, unlike LexAssist, I didn't start by writing code. I spent what felt like an unreasonably long time just on Phase 0 — architecture, database design, API design, security model, before touching a single controller. It felt slow. It was worth it. Every phase since has built cleanly on top of the last one, because the foundation was actually thought through instead of improvised.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's coming in this series
&lt;/h2&gt;

&lt;p&gt;In Part 2, I'll walk through the actual architecture decisions — why a modular monolith instead of microservices, how I designed the database schema (and the specific, recurring decision of when to embed data versus reference it, which came up constantly), and the tech stack choices and why each one earned its place instead of just being "what everyone uses."&lt;/p&gt;

&lt;p&gt;Part 3 is the part I'm most excited to write, because it's where the real engineering lives: a greedy algorithm for settling group expenses with the minimum number of transactions, a rule-based compatibility engine using HashSets and a Min-Heap for efficient Top-K matching, and the very deliberate security work behind real-time chat — making sure a Socket.IO room can't be joined by someone who was never actually invited.&lt;/p&gt;

&lt;p&gt;Part 4 will come once the project is further along — the honest version, including what broke, what I had to redo, and what I'd do differently.&lt;/p&gt;

&lt;p&gt;For now: the idea is set, the architecture is built, and the first several phases — auth, profiles, trips, discovery, matching, group formation, real-time chat, collaborative planning, and a working AI trip planner — are done and tested. LexAssist taught me what not to do. I'm hoping TravelMate is the proof that the lesson actually landed.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Next: Part 2 — Architecture, database design, and the tech decisions behind TravelMate.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>softwareengineering</category>
      <category>webdev</category>
      <category>programming</category>
      <category>studentprojects</category>
    </item>
  </channel>
</rss>
