<?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: Prince Singh</title>
    <description>The latest articles on DEV Community by Prince Singh (@prince_singh_1200563e78af).</description>
    <link>https://dev.to/prince_singh_1200563e78af</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%2F4160171%2F992fe3ff-acc0-4e7a-bdd4-7ccbe67d896e.png</url>
      <title>DEV Community: Prince Singh</title>
      <link>https://dev.to/prince_singh_1200563e78af</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/prince_singh_1200563e78af"/>
    <language>en</language>
    <item>
      <title>I built a trip planner so my friend group finally stops saying "let's go somewhere this long weekend"</title>
      <dc:creator>Prince Singh</dc:creator>
      <pubDate>Sun, 04 Oct 2026 19:40:00 +0000</pubDate>
      <link>https://dev.to/prince_singh_1200563e78af/i-built-a-trip-planner-so-my-friend-group-finally-stops-saying-lets-go-somewhere-this-long-2njh</link>
      <guid>https://dev.to/prince_singh_1200563e78af/i-built-a-trip-planner-so-my-friend-group-finally-stops-saying-lets-go-somewhere-this-long-2njh</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-weekend-2026-10-01"&gt;Hacktoberfest Weekend Challenge: Build for a Friend&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;Every long weekend, our group chat goes the same way. Someone says "let's go somewhere this time." Five people reply with a thumbs up. Nobody books anything. The weekend passes.&lt;/p&gt;

&lt;p&gt;The problem was never a lack of places to go. It was that someone has to take the lead, and nobody wants to be that person every time.&lt;/p&gt;

&lt;p&gt;So I built &lt;strong&gt;Trip Buddy&lt;/strong&gt;: a small tool that notices a long weekend coming up three weeks ahead, plans three different trips for my group of six friends, and emails each of us a vote. Once most of the group taps the same option, it's decided. Nobody had to lead.&lt;/p&gt;

&lt;p&gt;Trip Buddy is a Node.js app that runs on my laptop, with &lt;strong&gt;Gemma 4&lt;/strong&gt; running locally through Ollama as its brain. It is built for one specific group: six friends who meet in Delhi and leave from there.&lt;/p&gt;

&lt;p&gt;Here's what it does:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Finds the long weekends.&lt;/strong&gt; It reads the government holiday list for 2026 and 2027 and works out every window where a holiday joins a weekend.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Suggests bridge leave.&lt;/strong&gt; Dussehra 2026 falls on a Tuesday, so taking Monday off turns it into a 4-day trip. In April 2027, one day of leave gets you 5 days off. That line alone is what makes people reply.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Plans three different trips.&lt;/strong&gt; Gemma reads all six friends' preferences and suggests three trips with a different character each: hills, spiritual or nature, and heritage. Each comes with a day-by-day plan.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Emails everyone a personal vote.&lt;/strong&gt; Each friend gets their own email. If Gemma picked an option with them in mind, that card says so.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Counts the votes.&lt;/strong&gt; A tap on "I'm in" records the vote and shows a live tally. At 4 of 6, it announces the winner.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Runs on its own.&lt;/strong&gt; The server checks every six hours and emails the group 21 days before each long weekend, so there's time to apply for leave and book trains.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It also knows when &lt;em&gt;not&lt;/em&gt; to plan. Diwali is skipped both years, because nobody leaves home for a trip over Diwali.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;I haven't sent it to the real group yet, so this demo uses test inboxes (Gmail &lt;code&gt;+&lt;/code&gt; aliases) for all six friends. The votes below are mine, cast from each inbox to show the flow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The email each friend gets.&lt;/strong&gt; The subject line is the hook: &lt;em&gt;"Dussehra: take 1 day off, get 4 days (Sat 17 – Tue 20 Oct)".&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fl5ksr37gjrvxh0fmq03s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fl5ksr37gjrvxh0fmq03s.png" alt="Trip Buddy email for Dussehra showing three trip options, each with a day-by-day plan and an " width="800" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;After everyone votes.&lt;/strong&gt; One tap records the vote and shows the live tally.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fr9vdbmpa4f512k6v7bw0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fr9vdbmpa4f512k6v7bw0.png" alt="Vote tally page showing votes per destination and a message that the trip is decided" width="800" height="352"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Gemma planning the trip, locally.&lt;/strong&gt; Valid on the first attempt, in under three minutes on my laptop.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ft8jy46y4zep58m32whk5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ft8jy46y4zep58m32whk5.png" alt="Terminal output of Gemma planning the Dussehra trip locally, with three destinations, travel times and costs" width="799" height="278"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The code finds long weekends and bridge leave.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fe2o128eibnv7cp83tikr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fe2o128eibnv7cp83tikr.png" alt="Terminal output listing upcoming long weekends, with leave days needed for each" width="800" height="561"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Auto mode sending on its own.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F181jp0fra1gdrqjpjo2n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F181jp0fra1gdrqjpjo2n.png" alt="Server log showing auto mode detecting the Dussehra long weekend and sending emails to six friends" width="785" height="705"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/Princee215/Trip-Buddy" rel="noopener noreferrer"&gt;https://github.com/Princee215/Trip-Buddy&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To run it yourself: install Ollama, run &lt;code&gt;ollama pull gemma4&lt;/code&gt;, add your friends to &lt;code&gt;data/friends.json&lt;/code&gt;, put a Gmail App Password in &lt;code&gt;.env&lt;/code&gt;, and start &lt;code&gt;node src/server.js&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stack:&lt;/strong&gt; Gemma 4 (open-weight, Apache 2.0) via Ollama, Node.js, Express, Nodemailer, Cloudflare quick tunnel. No database, no paid APIs.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;p&gt;The core design rule: &lt;strong&gt;the model plans, the code enforces.&lt;/strong&gt; Gemma does the creative work. Plain JavaScript does everything that has a right answer.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Job&lt;/th&gt;
&lt;th&gt;Done by&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Which dates are long weekends&lt;/td&gt;
&lt;td&gt;Code&lt;/td&gt;
&lt;td&gt;Dates have one right answer. A model guessing weekdays would be wrong sometimes.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Which leave days to suggest&lt;/td&gt;
&lt;td&gt;Code&lt;/td&gt;
&lt;td&gt;A scoring rule: each leave day must earn about 1.5 extra days off.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Group profile&lt;/td&gt;
&lt;td&gt;Code&lt;/td&gt;
&lt;td&gt;Interests ranked by how many friends share them; veg needs counted.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Where to go and what to do&lt;/td&gt;
&lt;td&gt;Gemma&lt;/td&gt;
&lt;td&gt;Picking places that balance six people's tastes is the creative part.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Checking Gemma's answer&lt;/td&gt;
&lt;td&gt;Code&lt;/td&gt;
&lt;td&gt;Three options, each with a name and a day plan, or it retries.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Emails, votes, schedule&lt;/td&gt;
&lt;td&gt;Code&lt;/td&gt;
&lt;td&gt;Nodemailer, Express, a six-hour check.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The pipeline, in order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;planner.js&lt;/code&gt; marks each day as off or work, groups off days into runs, and joins nearby runs when the gap fits within 3 leave days. For each cluster, it keeps an "easy" option (no leave) and a "bridge" option (best value with leave).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;group.js&lt;/code&gt; turns six profiles into one group view.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;prompt.js&lt;/code&gt; writes a brief for Gemma: the trip window, the month, the return deadline, preferences, and accuracy rules.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;gemma.js&lt;/code&gt; calls Ollama's local API with &lt;code&gt;format: "json"&lt;/code&gt;, streaming on and thinking off.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;generate.js&lt;/code&gt; checks the structure, fixes small things in the code (trims or pads the day plan), and saves the plan so it's only generated once.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;email.js&lt;/code&gt; and &lt;code&gt;send.js&lt;/code&gt; build a personal email per friend and send it through Gmail.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;server.js&lt;/code&gt; records votes, shows the tally, and runs &lt;code&gt;auto.js&lt;/code&gt; every six hours.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;One rule in the prompt turned out to matter a lot: the group must be back in Delhi &lt;strong&gt;by 8 AM the morning after the trip&lt;/strong&gt;, because it's a working day. Gemma works backwards from that, so the last day of each plan says when to leave.&lt;/p&gt;

&lt;h3&gt;
  
  
  What Broke Along the Way
&lt;/h3&gt;

&lt;p&gt;Most of the interesting work was fixing things that went wrong.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;My scoring formula hid the best deal of the year.&lt;/strong&gt; The first version ranked trips by "days off per day of effort." It picked a plain 3-day weekend over Ram Navami plus Mahavir Jayanti in April 2027: 5 days off for 1 day of leave. I changed the score to &lt;code&gt;days − 1.5 × leaves&lt;/code&gt;, so a leave day has to earn its place.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Node gave up after 300 seconds.&lt;/strong&gt; My laptop took about 5 minutes per plan, and Node's built-in &lt;code&gt;fetch&lt;/code&gt; times out if the server is silent for 300 seconds. Two fixes: streaming, so words arrive as they're written, and &lt;code&gt;think: false&lt;/code&gt;, which skips Gemma's hidden reasoning. Plans dropped to under 3 minutes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I told Gemma 14 hours was fine, so it decided everything takes 14 hours.&lt;/strong&gt; When I allowed trips up to about 14 hours away, Gemma started saying Rishikesh takes 10–14 hours. It's about 5–6. The number in my prompt became an anchor. The fix was to say "closer places are equally good" and ask for the &lt;em&gt;realistic&lt;/em&gt; travel time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I turned preferences into rules, and my group would have corrected me.&lt;/strong&gt; Four of six of us drink, so I told Gemma to avoid alcohol-free towns. That ruled out Rishikesh and Mathura, which are great trips for us. Same with "mountains": everyone likes them, but not every trip has to be in the hills. Now the prompt has exactly one firm rule. Everyone has to be able to eat, because three of us are vegetarian. Everything else is a preference Gemma weighs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Strict checks made things worse.&lt;/strong&gt; My validator retried whenever travel time or budget went slightly over. Each retry cost minutes, for a 1-hour difference. Now only broken structure triggers a retry; everything else is a note, or fixed in code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Does Open Innovation Matter?
&lt;/h2&gt;

&lt;p&gt;I could have called a closed API. Running an open-weight model locally made this project better in four specific ways.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It costs nothing to run, forever.&lt;/strong&gt; This tool sends a handful of emails a year. Nobody in a friend group wants to pay a monthly API bill for that, and with Gemma on my own laptop, the cost is zero.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;My friends' data stays with me.&lt;/strong&gt; The tool knows each friend's budget, food habits, and whether they drink. That's the kind of thing friends tell each other, not a server they've never heard of. Here it never leaves my machine. The email footer says so.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The license lets me do anything with it.&lt;/strong&gt; Gemma 4 is released under Apache 2.0, so I can modify, share, or build on it with no strings. To be precise: it's an &lt;em&gt;open-weight&lt;/em&gt; model. The weights are open, but the training data isn't.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I can swap the model with one setting.&lt;/strong&gt; The model name is a single environment variable. If a better open model comes out next month, I change one line.&lt;/p&gt;

&lt;p&gt;The trade-off is real. A small local model gets local facts wrong, like Rishikesh travel times. It's also slower than a hosted API. That's exactly why the design keeps Gemma on the creative work and lets code handle anything with a right answer.&lt;/p&gt;

&lt;h3&gt;
  
  
  Limits and What's Next
&lt;/h3&gt;

&lt;p&gt;The honest limits of this weekend version:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;It only runs while my laptop is on.&lt;/strong&gt; That's the price of keeping everything local. A cheap always-on box, like an old laptop or a Raspberry Pi, would fix it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vote links break if the tunnel restarts.&lt;/strong&gt; I use a free Cloudflare quick tunnel, which gets a new URL every time. A named tunnel with a free account would keep the links stable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Travel times are estimates.&lt;/strong&gt; The email labels them "approx." and says to check before booking.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Holidays follow the central government list.&lt;/strong&gt; Some friends' companies have their own holiday calendars.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What I'd add next:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A preferences form, so friends update their own profile instead of replying to the email&lt;/li&gt;
&lt;li&gt;A "final plan" email the moment a trip wins the vote&lt;/li&gt;
&lt;li&gt;Per-friend travel to Delhi, for friends who live in other cities&lt;/li&gt;
&lt;li&gt;Grounding travel times with a search API, so Gemma stops guessing distances&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Prize Categories
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Gemma&lt;/strong&gt;: Gemma 4 runs locally through Ollama and does all the trip planning; nothing else in the project uses an AI model.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;The next long weekend is Guru Nanak Jayanti in November. Trip Buddy will email the group about it on its own, three weeks ahead. This time, nobody has to be the one who plans.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>weekendchallenge</category>
      <category>hacktoberfest</category>
      <category>hf26challenge</category>
    </item>
  </channel>
</rss>
