<?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: Devanshu P.</title>
    <description>The latest articles on DEV Community by Devanshu P. (@krdevanshu06).</description>
    <link>https://dev.to/krdevanshu06</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3068494%2F874ab9b8-46cb-4ce1-b5b4-66e2992c38e2.png</url>
      <title>DEV Community: Devanshu P.</title>
      <link>https://dev.to/krdevanshu06</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/krdevanshu06"/>
    <language>en</language>
    <item>
      <title>I Built an "Ethical" GitHub Streak Guardian (And How I Survived API Rate Limits)</title>
      <dc:creator>Devanshu P.</dc:creator>
      <pubDate>Sat, 22 Nov 2025 21:01:17 +0000</pubDate>
      <link>https://dev.to/krdevanshu06/i-built-an-ethical-github-streak-guardian-and-how-i-survived-api-rate-limits-4po</link>
      <guid>https://dev.to/krdevanshu06/i-built-an-ethical-github-streak-guardian-and-how-i-survived-api-rate-limits-4po</guid>
      <description>&lt;p&gt;We’ve all been there. You’re deep in the zone, debugging a race condition or refactoring a messy component. You code for 8 hours straight. You close your laptop, exhausted but proud.&lt;/p&gt;

&lt;p&gt;The next morning, you check your GitHub profile and see... &lt;strong&gt;a gray square.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You forgot to push. Your 100-day streak is gone. 📉&lt;/p&gt;

&lt;p&gt;I built &lt;strong&gt;&lt;a href="https://daily-diff.vercel.app/" rel="noopener noreferrer"&gt;DailyDiff&lt;/a&gt;&lt;/strong&gt; to solve this. But I didn't want to build just another "fake commit bot" that spams &lt;code&gt;update readme&lt;/code&gt; 50 times a day. I wanted to build a productivity companion that respects the spirit of open source while protecting your consistency.&lt;/p&gt;

&lt;p&gt;Here is a deep dive into how I built a full-stack, timezone-aware automation tool using &lt;strong&gt;React, Node.js, Supabase, and the GitHub GraphQL API.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  💡 The Core Concept: Ethical Automation
&lt;/h2&gt;

&lt;p&gt;Most streak savers are simple scripts that push empty commits. DailyDiff is different. It offers &lt;strong&gt;Content Strategies&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Learning Logs:&lt;/strong&gt; It can append what you learned that day to a repo.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Micro-Tasks:&lt;/strong&gt; Stuck in "coder's block"? It suggests real tasks (like "Refactor variable names" or "Add JSDoc") to unblock you.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Timezone Intelligence:&lt;/strong&gt; It knows &lt;em&gt;your&lt;/em&gt; day isn't over until it's midnight in &lt;em&gt;your&lt;/em&gt; city, not UTC.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  🛠 The Tech Stack
&lt;/h2&gt;

&lt;p&gt;I chose a distributed architecture to keep the frontend fast and the backend persistent.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Frontend:&lt;/strong&gt; React (Vite) + Tailwind CSS (deployed on &lt;strong&gt;Vercel&lt;/strong&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backend:&lt;/strong&gt; Node.js + Express (deployed on &lt;strong&gt;Render&lt;/strong&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Database:&lt;/strong&gt; Supabase (PostgreSQL) for storing user schedules and OAuth tokens.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automation:&lt;/strong&gt; &lt;code&gt;node-cron&lt;/code&gt; for background job scheduling.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auth:&lt;/strong&gt; GitHub OAuth 2.0.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🧠 Technical Deep Dive: The "Minor" Details That Matter
&lt;/h2&gt;

&lt;p&gt;Building a CRUD app is easy. Building a system that runs reliably in the background on free-tier infrastructure is where it gets interesting. Here are the three biggest engineering challenges I solved.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. The "Sleeping Server" Problem
&lt;/h3&gt;

&lt;p&gt;I deployed the backend to &lt;strong&gt;Render's Free Tier&lt;/strong&gt;. It’s great, but it has a catch: &lt;strong&gt;it spins down after 15 minutes of inactivity.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If my server is asleep, the Cron job responsible for checking commit schedules (&lt;code&gt;cron.schedule('* * * * *')&lt;/code&gt;) dies.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Solution: The Heartbeat Route&lt;/strong&gt;&lt;br&gt;
I added a lightweight health-check endpoint in Express:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// server/index.js&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;✅ DailyDiff Backend is Active&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, I set up an external monitor (using &lt;code&gt;cron-job.org&lt;/code&gt;) to ping this route every &lt;strong&gt;14 minutes&lt;/strong&gt;. This keeps the Render instance "warm" 24/7 without costing a dime, ensuring user automations never miss a beat.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Solving GitHub API Rate Limits (The Hybrid Cache)
&lt;/h3&gt;

&lt;p&gt;DailyDiff visualizes your contribution history using a beautiful heatmap. To render this, I fetch data using GitHub's &lt;strong&gt;GraphQL API&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The problem? fetching a year's worth of contribution data is expensive. During development (thanks to React Strict Mode double-invoking &lt;code&gt;useEffect&lt;/code&gt;), I hit GitHub's 5,000 req/hour limit constantly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Solution: A Hybrid Caching Strategy&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I implemented a two-layer cache to protect my API quota:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Layer 1: Client-Side (LocalStorage)&lt;/strong&gt;&lt;br&gt;
Before the frontend even talks to the server, it checks &lt;code&gt;localStorage&lt;/code&gt;. If valid data exists (less than 1 hour old), it renders instantly. 0ms latency, 0 API calls.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Layer 2: Server-Side (Disk Cache)&lt;/strong&gt;&lt;br&gt;
If the client cache misses, the request hits the server. The server checks a local JSON file (&lt;code&gt;cache_contributions.json&lt;/code&gt;). Even though Render has an ephemeral filesystem, this disk cache survives brief restarts and prevents the "thundering herd" problem if multiple clients connect simultaneously.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Code snippet from my caching logic&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cachedRaw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;CACHE_KEY&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cachedRaw&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cachedRaw&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;age&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;age&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;CACHE_DURATION&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Return early!&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Timezone-Aware Cron Jobs
&lt;/h3&gt;

&lt;p&gt;Servers run on UTC. Users do not.&lt;br&gt;
If a user in &lt;strong&gt;India (IST)&lt;/strong&gt; sets a reminder for &lt;strong&gt;11:00 PM&lt;/strong&gt;, but my server is in &lt;strong&gt;Oregon (UTC-7)&lt;/strong&gt;, a standard cron job fails.&lt;/p&gt;

&lt;p&gt;I couldn't just store &lt;code&gt;23:00&lt;/code&gt; in the database. I had to store the user's &lt;strong&gt;Timezone&lt;/strong&gt; (&lt;code&gt;Asia/Kolkata&lt;/code&gt;) alongside the time.&lt;/p&gt;

&lt;p&gt;In the backend cron loop, I don't check if &lt;code&gt;ServerTime == UserTime&lt;/code&gt;. instead, I dynamically convert the server's &lt;code&gt;now()&lt;/code&gt; into the user's local time before comparing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Inside the Cron Loop&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userTimeString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toLocaleTimeString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;en-US&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;timeZone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timezone&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// e.g., 'Asia/Kolkata'&lt;/span&gt;
  &lt;span class="na"&gt;hour&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2-digit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="na"&gt;minute&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2-digit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;hour12&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userTimeString&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;schedule_time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="c1"&gt;// Fire the commit!&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ensures that 8:00 PM feels like 8:00 PM, no matter where the server is located.&lt;/p&gt;




&lt;h2&gt;
  
  
  🎨 UI/UX: The "GitHub Dark Mode" Aesthetic
&lt;/h2&gt;

&lt;p&gt;I wanted the app to feel native to the developer ecosystem. I utilized &lt;strong&gt;Tailwind CSS&lt;/strong&gt; to mirror GitHub's specific dark mode color palette (&lt;code&gt;#0d1117&lt;/code&gt; for background, &lt;code&gt;#39d353&lt;/code&gt; for success states).&lt;/p&gt;

&lt;p&gt;I also implemented a &lt;strong&gt;React Portal&lt;/strong&gt; for the tooltips on the activity graph. Because the graph is in a container with &lt;code&gt;overflow-x: auto&lt;/code&gt; (for scrolling), a standard absolute tooltip would get clipped. Portaling it to &lt;code&gt;document.body&lt;/code&gt; allows it to float freely above the UI.&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 Deployment &amp;amp; Security
&lt;/h2&gt;

&lt;p&gt;Deploying a separated frontend and backend required strict &lt;strong&gt;CORS&lt;/strong&gt; and &lt;strong&gt;Cookie&lt;/strong&gt; configuration.&lt;/p&gt;

&lt;p&gt;Since the frontend (&lt;code&gt;vercel.app&lt;/code&gt;) and backend (&lt;code&gt;onrender.com&lt;/code&gt;) are on different domains, I had to set the session cookies to &lt;code&gt;SameSite: none&lt;/code&gt; and &lt;code&gt;Secure: true&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;cookieSession&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;session&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SESSION_SECRET&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="c1"&gt;// Required for cross-site cookies between Vercel and Render&lt;/span&gt;
  &lt;span class="na"&gt;sameSite&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NODE_ENV&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;production&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;none&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lax&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;secure&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NODE_ENV&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;production&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="na"&gt;httpOnly&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🔮 What's Next?
&lt;/h2&gt;

&lt;p&gt;DailyDiff is currently in &lt;strong&gt;v1&lt;/strong&gt;. I'm planning to add:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AI-Generated Commit Content:&lt;/strong&gt; Using OpenAI to read the user's actual code changes and suggest commit messages.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Team Leaderboards:&lt;/strong&gt; Gamifying the streak experience.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🔗 Links
&lt;/h2&gt;

&lt;p&gt;This project is fully open-source. I’d love for you to check out the code, fork it, or give it a star if you find it useful!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Live Demo:&lt;/strong&gt; &lt;a href="https://www.google.com/search?q=https://daily-diff.vercel.app/" rel="noopener noreferrer"&gt;https://daily-diff.vercel.app/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub Repo:&lt;/strong&gt; &lt;a href="https://www.google.com/search?q=https://github.com/KrDevanshu06/dailydiff" rel="noopener noreferrer"&gt;https://github.com/KrDevanshu06/dailydiff&lt;/a&gt; Star it.🌟&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks for reading! Let me know in the comments—have you ever lost a 100+ day streak? 😅&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>productivity</category>
      <category>javascript</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Career Companion: A GenAI-Powered Assistant for College Students</title>
      <dc:creator>Devanshu P.</dc:creator>
      <pubDate>Sun, 20 Apr 2025 13:44:55 +0000</pubDate>
      <link>https://dev.to/krdevanshu06/career-companion-a-genai-powered-assistant-for-college-students-1oem</link>
      <guid>https://dev.to/krdevanshu06/career-companion-a-genai-powered-assistant-for-college-students-1oem</guid>
      <description>&lt;p&gt;🎓 &lt;strong&gt;Career Companion&lt;/strong&gt; is an interactive GenAI-powered assistant designed to help &lt;strong&gt;college students&lt;/strong&gt; with personalized career guidance, course suggestions, and tech pathway insights — all powered by cutting-edge generative AI tools and hosted on &lt;strong&gt;Kaggle Notebooks&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 Project Overview
&lt;/h2&gt;

&lt;p&gt;As part of my Generative AI Capstone Project, I built a &lt;strong&gt;Career Companion Assistant&lt;/strong&gt; that simulates interactive Q&amp;amp;A sessions for college students, helping them explore the right career choices and resources in real-time using Large Language Models (LLMs).&lt;/p&gt;

&lt;p&gt;The assistant supports both &lt;strong&gt;chat-based interaction&lt;/strong&gt; and &lt;strong&gt;form-driven recommendations&lt;/strong&gt;, making it beginner-friendly and effective even without real-time UI deployment.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧠 Key GenAI Capabilities Demonstrated
&lt;/h2&gt;

&lt;p&gt;This project integrates &lt;strong&gt;three core GenAI capabilities&lt;/strong&gt;:&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ 1. &lt;strong&gt;Few-shot Prompting&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The assistant uses prompt engineering to provide consistent responses with career suggestions, even for ambiguous or brief questions.&lt;/li&gt;
&lt;li&gt;Includes career role templates (e.g., software engineer, data analyst, cloud engineer) with predefined suggestions and courses.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ✅ 2. &lt;strong&gt;Structured Output (Controlled Generation)&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Responses are formatted in a consistent, structured way (lists, markdown tables, and sections).&lt;/li&gt;
&lt;li&gt;Useful for logging into CSV files and analyzing student needs.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ✅ 3. &lt;strong&gt;Retrieval Augmented Generation (RAG)&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Simulated document lookup and embeddings are used to enrich the assistant's answers.&lt;/li&gt;
&lt;li&gt;Students can get domain-specific insights like tech stacks, roadmap links, and certifications.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🧰 Tools &amp;amp; Technologies Used
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;🧠 Gemini Pro (via API) – for LLM-based Q&amp;amp;A&lt;/li&gt;
&lt;li&gt;🐍 Python &amp;amp; Pandas – for backend logic and chat logging&lt;/li&gt;
&lt;li&gt;📊 Kaggle Notebooks – as the main interactive environment&lt;/li&gt;
&lt;li&gt;📄 CSV Export – to save Q&amp;amp;A logs for further analysis&lt;/li&gt;
&lt;li&gt;🔗 Markdown display – to show responses in clean UI format&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  💡 How It Works (with Screenshots)
&lt;/h2&gt;

&lt;p&gt;The project runs inside a Kaggle Notebook with the following components:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Model Initialization&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sets up Gemini Pro API and context for responses.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Prompt Handling Function&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A function handles user prompts (dummy input block on Kaggle) and logs responses.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Response Generator&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Calls the model and uses prompt templates for consistent responses.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Chat Logging&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Stores every Q&amp;amp;A in a Pandas DataFrame and saves it as &lt;code&gt;career_chat_log.csv&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Download Link&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Allows users to download the full session as a log file from Kaggle.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  📷 Screenshots
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Setup block with Gemini Pro key&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&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.amazonaws.com%2Fuploads%2Farticles%2F1x5qij749s1gbvgv89yl.png" alt="Setup block with Gemini Pro key" width="800" height="360"&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Sample Q&amp;amp;A block in notebook&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&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.amazonaws.com%2Fuploads%2Farticles%2Fhl0fq5wk8vrqe580kzs0.png" alt="Sample Q&amp;amp;A block in notebook" width="800" height="460"&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Downloadable log file&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&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.amazonaws.com%2Fuploads%2Farticles%2Fhkeiuy836mzna4y7iwa6.png" alt="Downloadable log file" width="800" height="258"&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Structured response with markdown&lt;/li&gt;
&lt;/ul&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.amazonaws.com%2Fuploads%2Farticles%2Fd7613qbskyyen1pxe271.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.amazonaws.com%2Fuploads%2Farticles%2Fd7613qbskyyen1pxe271.png" alt="Structured response with markdown" width="790" height="518"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🔍 Sample Output
&lt;/h2&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.amazonaws.com%2Fuploads%2Farticles%2Fdlgnm1ztn8yxtzw7jpgd.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.amazonaws.com%2Fuploads%2Farticles%2Fdlgnm1ztn8yxtzw7jpgd.png" alt="Sample Output" width="800" height="440"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🔗 Try the Project
&lt;/h2&gt;

&lt;p&gt;You can view the full notebook here:&lt;br&gt;&lt;br&gt;
👉 &lt;a href="https://www.kaggle.com/code/devanshukumarprasad/genai-capstone-project-career-companion" rel="noopener noreferrer"&gt;Kaggle Notebook Link&lt;/a&gt; &lt;/p&gt;




&lt;h2&gt;
  
  
  📚 What I Learned
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;How to use LLMs with few-shot prompting&lt;/li&gt;
&lt;li&gt;Creating structured logs for better analysis&lt;/li&gt;
&lt;li&gt;Simulating interaction in a non-UI environment like Kaggle&lt;/li&gt;
&lt;li&gt;Basics of Retrieval Augmented Generation (RAG)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🛠 Improvements Planned
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Integrate embeddings using FAISS/ChromaDB&lt;/li&gt;
&lt;li&gt;Use Streamlit or Gradio for web UI&lt;/li&gt;
&lt;li&gt;Allow real-time user input with context memory&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ✅ GenAI Capabilities Recap
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Capability&lt;/th&gt;
&lt;th&gt;Used&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;✅ Structured Output&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;✅ Few-shot Prompting&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;✅ RAG&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  🙌 Final Thoughts
&lt;/h2&gt;

&lt;p&gt;GenAI isn't just about fancy chatbots — it can truly empower students by providing &lt;strong&gt;context-aware, structured, and actionable guidance&lt;/strong&gt;. This project gave me real-world insight into building domain-specific assistants using the power of generative AI.&lt;/p&gt;

&lt;p&gt;If you're a student looking to get into AI, education tech, or LLM apps — start experimenting today!&lt;/p&gt;




&lt;p&gt;📬 Feel free to connect or ask questions in the comments!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.linkedin.com/in/KrDevanshu06/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/KrDevanshu06" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;br&gt;
&lt;a href="https://x.com/KrDevanshu06" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.kaggle.com/devanshukumarprasad/" rel="noopener noreferrer"&gt;Kaggle&lt;/a&gt;&lt;/p&gt;

</description>
      <category>programming</category>
      <category>ai</category>
      <category>machinelearning</category>
      <category>genai</category>
    </item>
  </channel>
</rss>
