<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[SKB Codes]]></title><description><![CDATA[This is my coding journey and my personal projects that I want to share with the world.]]></description><link>https://skb3611.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Mon, 19 Oct 2026 07:44:18 GMT</lastBuildDate><atom:link href="https://skb3611.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[GitFolio Relaunch: Create Your Developer Portfolio From GitHub in Seconds]]></title><description><![CDATA[Building a professional developer portfolio shouldn't mean spending hours designing a website. With GitFolio, you can turn your GitHub profile into a polished, hosted developer portfolio in seconds.
W]]></description><link>https://skb3611.hashnode.dev/gitfolio-relaunch-create-your-developer-portfolio-from-github-in-seconds</link><guid isPermaLink="true">https://skb3611.hashnode.dev/gitfolio-relaunch-create-your-developer-portfolio-from-github-in-seconds</guid><category><![CDATA[GitHub]]></category><category><![CDATA[SaaS]]></category><category><![CDATA[Developer Tools]]></category><category><![CDATA[Developer]]></category><category><![CDATA[portfolio]]></category><dc:creator><![CDATA[Shubham Bhilare]]></dc:creator><pubDate>Sat, 17 Oct 2026 08:07:33 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6824829e98c516efc633ce1c/2a27029e-9dfd-4866-88a4-381aec3c0d1f.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Building a professional developer portfolio shouldn't mean spending hours designing a website. With <strong>GitFolio</strong>, you can turn your GitHub profile into a polished, hosted developer portfolio in seconds.</p>
<p>We're excited to relaunch <a href="https://gitfolio.in">GitFolio</a> with new features and payment support, making it easier for developers to showcase their projects, skills, and experience online.</p>
<h3>From GitHub to a Professional Portfolio</h3>
<p>GitFolio connects with your GitHub account, helps you choose from developer portfolio templates, and gives you a professional website you can share with recruiters, clients, and the developer community.</p>
<p>Whether you're a student building your first portfolio, a freelancer showcasing projects, or an experienced software engineer, GitFolio helps you establish your online presence without building everything from scratch.</p>
<h3>What's New With GitFolio?</h3>
<ul>
<li><p><strong>Developer portfolio templates:</strong> Choose a design that matches your style.</p>
</li>
<li><p><strong>GitHub integration:</strong> Turn your developer profile and repositories into a portfolio.</p>
</li>
<li><p><strong>Hosted portfolio websites:</strong> Publish and share your work online.</p>
</li>
<li><p><strong>Payment support:</strong> Access paid template options with supported payment methods.</p>
</li>
</ul>
<h3>Build Less. Showcase More.</h3>
<p>Your projects deserve more than a list of repositories. Give them a professional home with a portfolio website built around your work.</p>
<p><strong>GitFolio is back. Create your developer portfolio today.</strong></p>
<p>Visit <a href="https://gitfolio.in">https://gitfolio.in</a> and turn your GitHub into a portfolio that speaks for itself.</p>
]]></content:encoded></item><item><title><![CDATA[GitFolio - Dev Portfolio in Seconds]]></title><description><![CDATA[👋Introduction
As a developer all we have is our Github porfile! We spend hours building our products, do open-source and pushing to prod... but when its time to show our work, all we have is the same github profile.
So to solve this problem, I'll li...]]></description><link>https://skb3611.hashnode.dev/gitfolio-dev-portfolio-in-seconds</link><guid isPermaLink="true">https://skb3611.hashnode.dev/gitfolio-dev-portfolio-in-seconds</guid><category><![CDATA[GitHub]]></category><category><![CDATA[portfolio]]></category><category><![CDATA[Developer]]></category><category><![CDATA[SaaS]]></category><category><![CDATA[Developer Tools]]></category><dc:creator><![CDATA[Shubham Bhilare]]></dc:creator><pubDate>Sun, 03 Aug 2025 12:24:33 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1754164050581/b0cc6505-573f-4de2-892d-0548ccaf7bbe.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">👋Introduction</h2>
<p>As a developer all we have is our <strong><em>Github</em></strong> porfile! We spend hours building our products, do <em>open-source</em> and pushing to prod... but when its time to show our work, all we have is the same <strong><em>github profile</em></strong>.</p>
<p>So to solve this problem, I'll like to introduce you to <a target="_blank" href="https://gitfolio-dev.vercel.app"><strong><em>GitFolio</em></strong></a> with the vision of <strong><em>"Turning Your Github Profile into Portfolio Sites in Seconds."</em></strong> No coding, No Markdown. Just Connect your <strong><em>Github</em></strong>,select a <strong><em>template</em></strong>, and <strong><em>boom 💥</em></strong> your site is <strong><em>live✅</em></strong>.</p>
<h3 id="heading-what-is-gitfolio">🚀 What is GitFolio?</h3>
<p>GitFolio is a free to use platform that helps you showcase your <strong><em>Github</em></strong> profile in an amazing way !</p>
<blockquote>
<p>Because <em>Your GitHub already tells your story — now turnit into a personal site that speaks for itself</em></p>
</blockquote>
<h3 id="heading-why-i-built-gitfolio">Why I Built GitFolio ?</h3>
<p>I've seen many developers, including myself ignoring making personal portfolio sites. Rather than that they focus on building new projects/products. They do not want to invest time in making portfolio websites and maintaining it. Meanwhile, <em>Github</em> already contains 90% of your data, projects, skills, contributions and many more... So why not use it ?</p>
<p>So I thought of making a platform that'll help developers including myself , in creating and maintaining of the _personal portfolio <em>site with a</em> <strong><em>live hosted URl</em></strong> <em>just by connecting</em> <strong><em>Github!</em></strong> .</p>
<blockquote>
<p><a target="_blank" href="https://gitfolio-template.vercel.app/Black%20&amp;%20White/Skb3611">Sample Portfolio</a></p>
</blockquote>
<h3 id="heading-how-it-works">How it Works ⚙️</h3>
<ol>
<li><p>Connect your <strong><em>Github</em></strong> account. <em>(read-only-access ||no scary permissions and private repos initially)</em></p>
</li>
<li><p>Pick a Template <em>(Clean modern responsive templates available - currently launching with 1 template)</em></p>
</li>
<li><p>Done ✅ - <em>You're Live</em> <em>(Copy your public access link or just visit your portfolio.)</em></p>
</li>
</ol>
<h3 id="heading-features">Features</h3>
<ul>
<li><p>GitHub-powered Data</p>
</li>
<li><p>Personal Dashboard for necessary changes.</p>
</li>
<li><p>Clean , mobile-responsive templates. (Currently only 1 available)</p>
</li>
<li><p>Instant deploy (no build process, ready within seconds !)</p>
</li>
<li><p>Shareable public links</p>
</li>
</ul>
<h3 id="heading-who-its-for">Who It's For?</h3>
<ul>
<li><p>All Developer Community</p>
</li>
<li><p>Students applying for internships</p>
</li>
<li><p>Anyone who has got less time and need a portfolio on urgent basis</p>
</li>
<li><p>Every developer who wants their online presence</p>
</li>
</ul>
<h3 id="heading-whats-upcoming">Whats Upcoming?</h3>
<ul>
<li><p>Multiple templates</p>
</li>
<li><p>Real time data - sync from <strong><em>Github</em></strong></p>
</li>
<li><p>Auto Generated SEO support and many more ...</p>
</li>
</ul>
<blockquote>
<p>If you’ve got a GitHub, you’ve already got a portfolio — GitFolio just brings it to life.</p>
</blockquote>
<h3 id="heading-help-me-improve-it">Help Me Improve It 📢</h3>
<p>GitFolio is still in its early MVP phase. I’d love feedback, suggestions, and early users!</p>
<p><a target="_blank" href="http://gitfolio-dev.vercel.app">Visit GitFolio</a></p>
<p><a target="_blank" href="https://www.linkedin.com/in/shubham-bhilare-0a694a309/">Connect on Linkedin</a></p>
<p><a target="_blank" href="https://x.com/SKB3611">Connect on Twitter</a></p>
<h3 id="heading-final-thoughts">Final Thoughts 💬</h3>
<p>In a world where “you are what you ship,” your portfolio matters.</p>
<p>GitFolio helps you show what you’ve built — without building the portfolio itself.</p>
<p>If you try it, tweet me or tag me with your portfolio — I’d love to share it. Let’s help more devs put themselves out there. 🚀</p>
]]></content:encoded></item><item><title><![CDATA[Mastering AWS S3 with JavaScript: S3Client Config & Most Useful Commands 🚀]]></title><description><![CDATA[Whether you're building a full-stack app or managing static assets, Amazon S3 is a go-to service for scalable storage. In this post, we’ll break down:

📦 S3Client setup (with @aws-sdk/client-s3)
⚙️ Most useful operations: creating/deleting buckets, ...]]></description><link>https://skb3611.hashnode.dev/mastering-aws-s3-with-javascript-s3client-config-and-most-useful-commands</link><guid isPermaLink="true">https://skb3611.hashnode.dev/mastering-aws-s3-with-javascript-s3client-config-and-most-useful-commands</guid><category><![CDATA[Cloud]]></category><category><![CDATA[Cloud Computing]]></category><category><![CDATA[AWS]]></category><category><![CDATA[AWS s3]]></category><dc:creator><![CDATA[Shubham Bhilare]]></dc:creator><pubDate>Thu, 05 Jun 2025 07:41:01 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/5Xwaj9gaR0g/upload/b83f6c63195d263a4996340e05bd35b0.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Whether you're building a full-stack app or managing static assets, <strong>Amazon S3</strong> is a go-to service for scalable storage. In this post, we’ll break down:</p>
<ul>
<li>📦 S3Client setup (with <code>@aws-sdk/client-s3</code>)</li>
<li>⚙️ Most useful operations: creating/deleting buckets, uploading/downloading files</li>
<li>🔁 A simple workflow you can apply to your own app</li>
</ul>
<hr />
<h2 id="heading-setting-up-the-aws-s3-client">🔧 Setting Up the AWS S3 Client</h2>
<p>First, install the SDK:</p>
<pre><code class="lang-bash">npm install @aws-sdk/client-s3
</code></pre>
<p>Then configure your client:</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// config/s3Client.js</span>
<span class="hljs-keyword">import</span> { S3Client } <span class="hljs-keyword">from</span> <span class="hljs-string">'@aws-sdk/client-s3'</span>;

<span class="hljs-keyword">const</span> s3Client = <span class="hljs-keyword">new</span> S3Client({
  <span class="hljs-attr">region</span>: <span class="hljs-string">'your-region'</span>, <span class="hljs-comment">// e.g., 'us-east-1'</span>
  <span class="hljs-attr">credentials</span>: {
    <span class="hljs-attr">accessKeyId</span>: process.env.AWS_ACCESS_KEY_ID,
    <span class="hljs-attr">secretAccessKey</span>: process.env.AWS_SECRET_ACCESS_KEY
  },
});

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> s3Client;
</code></pre>
<blockquote>
<p>💡 Best Practice: Store your credentials securely using environment variables or IAM roles (if you're using Lambda/EC2).</p>
</blockquote>
<hr />
<h2 id="heading-most-useful-s3-commands">📚 Most Useful S3 Commands</h2>
<h3 id="heading-1-create-a-bucket">✅ 1. Create a Bucket</h3>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { CreateBucketCommand } <span class="hljs-keyword">from</span> <span class="hljs-string">'@aws-sdk/client-s3'</span>;

<span class="hljs-keyword">await</span> s3Client.send(<span class="hljs-keyword">new</span> CreateBucketCommand({
  <span class="hljs-attr">Bucket</span>: <span class="hljs-string">'my-awesome-bucket'</span>,
}));
</code></pre>
<h3 id="heading-2-delete-a-bucket">🗑️ 2. Delete a Bucket</h3>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { DeleteBucketCommand } <span class="hljs-keyword">from</span> <span class="hljs-string">'@aws-sdk/client-s3'</span>;

<span class="hljs-keyword">await</span> s3Client.send(<span class="hljs-keyword">new</span> DeleteBucketCommand({
  <span class="hljs-attr">Bucket</span>: <span class="hljs-string">'my-awesome-bucket'</span>,
}));
</code></pre>
<h3 id="heading-3-upload-an-object">📤 3. Upload an Object</h3>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { PutObjectCommand } <span class="hljs-keyword">from</span> <span class="hljs-string">'@aws-sdk/client-s3'</span>;
<span class="hljs-keyword">import</span> fs <span class="hljs-keyword">from</span> <span class="hljs-string">'fs'</span>;

<span class="hljs-keyword">const</span> fileStream = fs.createReadStream(<span class="hljs-string">'./example.txt'</span>);

<span class="hljs-keyword">await</span> s3Client.send(<span class="hljs-keyword">new</span> PutObjectCommand({
  <span class="hljs-attr">Bucket</span>: <span class="hljs-string">'my-awesome-bucket'</span>,
  <span class="hljs-attr">Key</span>: <span class="hljs-string">'example.txt'</span>,
  <span class="hljs-attr">Body</span>: fileStream,
}));
</code></pre>
<h3 id="heading-4-download-an-object">📥 4. Download an Object</h3>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { GetObjectCommand } <span class="hljs-keyword">from</span> <span class="hljs-string">'@aws-sdk/client-s3'</span>;
<span class="hljs-keyword">import</span> fs <span class="hljs-keyword">from</span> <span class="hljs-string">'fs'</span>;

<span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> s3Client.send(<span class="hljs-keyword">new</span> GetObjectCommand({
  <span class="hljs-attr">Bucket</span>: <span class="hljs-string">'my-awesome-bucket'</span>,
  <span class="hljs-attr">Key</span>: <span class="hljs-string">'example.txt'</span>,
}));

response.Body.pipe(fs.createWriteStream(<span class="hljs-string">'./downloaded.txt'</span>));
</code></pre>
<h3 id="heading-5-delete-an-object">❌ 5. Delete an Object</h3>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { DeleteObjectCommand } <span class="hljs-keyword">from</span> <span class="hljs-string">'@aws-sdk/client-s3'</span>;

<span class="hljs-keyword">await</span> s3Client.send(<span class="hljs-keyword">new</span> DeleteObjectCommand({
  <span class="hljs-attr">Bucket</span>: <span class="hljs-string">'my-awesome-bucket'</span>,
  <span class="hljs-attr">Key</span>: <span class="hljs-string">'example.txt'</span>,
}));
</code></pre>
<h3 id="heading-6-list-objects-in-a-bucket">📃 6. List Objects in a Bucket</h3>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { ListObjectsV2Command } <span class="hljs-keyword">from</span> <span class="hljs-string">'@aws-sdk/client-s3'</span>;

<span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> s3Client.send(<span class="hljs-keyword">new</span> ListObjectsV2Command({
  <span class="hljs-attr">Bucket</span>: <span class="hljs-string">'my-awesome-bucket'</span>,
}));

<span class="hljs-built_in">console</span>.log(response.Contents);
</code></pre>
<hr />
<h2 id="heading-workflow-example-image-upload-api">🧠 Workflow Example: Image Upload API</h2>
<p>Here’s a simple idea of how your workflow could look in a backend:</p>
<ol>
<li><strong>User uploads an image</strong></li>
<li><strong>Frontend sends file to backend</strong></li>
<li><strong>Backend uploads file to S3</strong></li>
<li><strong>S3 returns URL</strong></li>
<li><strong>URL saved in DB</strong></li>
<li><strong>URL sent back to frontend</strong></li>
</ol>
<pre><code class="lang-jsx"><span class="hljs-comment">// Upload and return URL</span>
<span class="hljs-keyword">const</span> uploadToS3 = <span class="hljs-keyword">async</span> (file, key) =&gt; {
  <span class="hljs-keyword">await</span> s3Client.send(<span class="hljs-keyword">new</span> PutObjectCommand({
    <span class="hljs-attr">Bucket</span>: <span class="hljs-string">'my-awesome-bucket'</span>,
    <span class="hljs-attr">Key</span>: key,
    <span class="hljs-attr">Body</span>: file.buffer,
    <span class="hljs-attr">ContentType</span>: file.mimetype,
  }));

  <span class="hljs-keyword">return</span> <span class="hljs-string">`https://<span class="hljs-subst">${yourBucket}</span>.s3.<span class="hljs-subst">${yourRegion}</span>.amazonaws.com/<span class="hljs-subst">${key}</span>`</span>;
};
</code></pre>
<hr />
<h2 id="heading-extra-commands-to-explore">🧪 Extra Commands to Explore</h2>
<ul>
<li><code>CopyObjectCommand</code> – Duplicate files</li>
<li><code>HeadObjectCommand</code> – Check if file exists</li>
<li><code>PutObjectAclCommand</code> – Make file public</li>
<li>Multipart Upload – For large files (&gt;5MB)</li>
</ul>
<hr />
<h2 id="heading-final-thoughts">✅ Final Thoughts</h2>
<p>The AWS SDK v3 makes working with S3 modular and easy. With the right config and a clean workflow, integrating S3 into your app is seamless. If you’re building a file uploader, static hosting solution, or media management API—this toolkit is all you need to start strong.</p>
<blockquote>
<p>💬 Have questions or want to see this workflow in Express, Next.js, or NestJS? Drop a comment!</p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[How to Fix LinkedIn Authentication in NextAuth.js: A Custom Provider Setup Guide]]></title><description><![CDATA[👋 Introduction
While working on my Resume Builder App using Next.js and NextAuth, I encountered a major issue integrating LinkedIn as a provider. The default implementation of the LinkedInProvider from next-auth/providers simply didn't work as expec...]]></description><link>https://skb3611.hashnode.dev/linkedin-authentication-in-nextauthjs</link><guid isPermaLink="true">https://skb3611.hashnode.dev/linkedin-authentication-in-nextauthjs</guid><category><![CDATA[#nextjs #nextauth #linkedin #oauth2 #webdevelopment #authentication]]></category><dc:creator><![CDATA[Shubham Bhilare]]></dc:creator><pubDate>Sat, 17 May 2025 21:34:51 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1747517539717/b5a9d01a-b244-485f-a228-a578de8a00d5.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-introduction">👋 Introduction</h3>
<p>While working on my <strong>Resume Builder App</strong> using <code>Next.js</code> and <code>NextAuth</code>, I encountered a major issue integrating <strong>LinkedIn as a provider</strong>. The default implementation of the <code>LinkedInProvider</code> from <code>next-auth/providers</code> simply didn't work as expected — especially when it came to retrieving email and profile data.</p>
<p>So I dug deep into the LinkedIn OAuth documentation and crafted a <strong>fully working custom provider setup</strong>, which I’m sharing in this blog post to help others facing similar issues.</p>
<h3 id="heading-the-problem-default-linkedinprovider-didnt-work">🚫 The Problem: Default LinkedInProvider Didn’t Work</h3>
<p>Here’s what the <strong>default example</strong> from the <a target="_blank" href="https://next-auth.js.org/providers/linkedin">NextAuth</a> docs looked like:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> LinkedInProvider <span class="hljs-keyword">from</span> <span class="hljs-string">"next-auth/providers/linkedin"</span>;

providers: [
  LinkedInProvider({
    <span class="hljs-attr">clientId</span>: process.env.LINKEDIN_CLIENT_ID,
    <span class="hljs-attr">clientSecret</span>: process.env.LINKEDIN_CLIENT_SECRET
  })
]
</code></pre>
<p>This might work in <em>some</em> cases, but if you're expecting to get detailed <strong>user profile fields</strong> like name, email, and profile picture — you'll be disappointed.</p>
<h3 id="heading-the-solution-custom-linkedin-provider">✅ The Solution: Custom LinkedIn Provider</h3>
<p>After reviewing the OAuth 2.0 specs and LinkedIn’s API docs, here’s the working solution I implemented:</p>
<pre><code class="lang-javascript">LinkedInProvider({
  <span class="hljs-attr">clientId</span>: process.env.LINKEDIN_CLIENT_ID ?? <span class="hljs-string">""</span>,
  <span class="hljs-attr">clientSecret</span>: process.env.LINKEDIN_CLIENT_SECRET ?? <span class="hljs-string">""</span>,
  <span class="hljs-attr">client</span>: { <span class="hljs-attr">token_endpoint_auth_method</span>: <span class="hljs-string">"client_secret_post"</span> },
  <span class="hljs-attr">scope</span>: <span class="hljs-string">"r_liteprofile r_emailaddress"</span>,
  <span class="hljs-attr">issuer</span>: <span class="hljs-string">"https://www.linkedin.com"</span>,
  <span class="hljs-attr">userinfo</span>: {
    <span class="hljs-attr">url</span>: <span class="hljs-string">"https://api.linkedin.com/v2/userinfo"</span>,
  },
  <span class="hljs-attr">token</span>: {
    <span class="hljs-attr">url</span>: <span class="hljs-string">"https://www.linkedin.com/oauth/v2/accessToken"</span>,
  },
  <span class="hljs-attr">wellKnown</span>: <span class="hljs-string">"https://www.linkedin.com/oauth/.well-known/openid-configuration"</span>,
  <span class="hljs-attr">authorization</span>: {
    <span class="hljs-attr">url</span>: <span class="hljs-string">"https://www.linkedin.com/oauth/v2/authorization"</span>,
    <span class="hljs-attr">params</span>: {
      <span class="hljs-attr">scope</span>: <span class="hljs-string">"profile email openid"</span>,
      <span class="hljs-attr">prompt</span>: <span class="hljs-string">"consent"</span>,
      <span class="hljs-attr">access_type</span>: <span class="hljs-string">"offline"</span>,
      <span class="hljs-attr">response_type</span>: <span class="hljs-string">"code"</span>,
    },
  },
  <span class="hljs-attr">jwks_endpoint</span>: <span class="hljs-string">"https://www.linkedin.com/oauth/openid/jwks"</span>,
  <span class="hljs-keyword">async</span> profile(profile) {
    <span class="hljs-keyword">return</span> {
      <span class="hljs-attr">id</span>: profile.sub,
      <span class="hljs-attr">name</span>: profile.name,
      <span class="hljs-attr">firstname</span>: profile.given_name,
      <span class="hljs-attr">lastname</span>: profile.family_name,
      <span class="hljs-attr">email</span>: profile.email,
      <span class="hljs-attr">image</span>: profile.picture,
    };
  },
});
</code></pre>
<h3 id="heading-why-this-works">🛠️ Why This Works</h3>
<ul>
<li><p>✅ Explicit scopes (<code>r_emailaddress</code>, <code>r_liteprofile</code>) ensure proper permissions</p>
</li>
<li><p>✅ Manually defines <code>userinfo</code>, <code>token</code>, and <code>authorization</code> endpoints</p>
</li>
<li><p>✅ Provides a <code>profile()</code> function to format LinkedIn's response correctly</p>
</li>
<li><p>✅ Uses <code>client_secret_post</code> to avoid authorization issues with LinkedIn</p>
</li>
</ul>
<h3 id="heading-final-thoughts">🚀 Final Thoughts</h3>
<p>OAuth can be frustrating — especially with providers like LinkedIn that don’t always play nicely out of the box. This custom provider setup saved my project, and I hope it helps yours too.</p>
<p>Feel free to check out my full project <a target="_blank" href="https://resume-org.vercel.app/">here</a> and leave any feedback!</p>
<hr />
<p><strong>Thanks for reading!</strong><br />— Shubham (SKB)</p>
]]></content:encoded></item><item><title><![CDATA[How I Created a Full-Stack Resume Builder Using Next.js and Prisma]]></title><description><![CDATA[🚀 Live Demo: https://resume-org.vercel.app
Introduction
Building a resume can be a tedious task, especially when you want a polished, professional look without spending hours on formatting. To solve this, I decided to create a full-stack Resume Buil...]]></description><link>https://skb3611.hashnode.dev/how-i-created-a-full-stack-resume-builder-using-nextjs-and-prisma</link><guid isPermaLink="true">https://skb3611.hashnode.dev/how-i-created-a-full-stack-resume-builder-using-nextjs-and-prisma</guid><category><![CDATA[#Nextjs #Prisma #WebDev #React #FullStack #SideProject]]></category><dc:creator><![CDATA[Shubham Bhilare]]></dc:creator><pubDate>Fri, 16 May 2025 21:35:24 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1747431191780/6fe67ef4-ac05-4e35-bf64-3c8e542681c0.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>🚀 <strong>Live Demo:</strong> <a target="_blank" href="https://resume-org.vercel.app">https://resume-org.vercel.app</a></p>
<h2 id="heading-introduction">Introduction</h2>
<p>Building a resume can be a tedious task, especially when you want a polished, professional look without spending hours on formatting. To solve this, I decided to create a <strong>full-stack Resume Builder</strong> web app that offers users multiple templates, a dynamic editor, and seamless export to PDF.</p>
<p>In this post, I’ll share the features, tech stack, challenges, and future plans of this project, along with a live demo you can try out yourself.</p>
<h2 id="heading-tech-stack-overview">Tech Stack Overview</h2>
<p>To build a modern, scalable application, I chose the following technologies:</p>
<ul>
<li><p><strong>Next.js</strong> — For both frontend and backend with React and API routes</p>
</li>
<li><p><strong>Prisma ORM</strong> — To manage PostgreSQL database schema and queries efficiently</p>
</li>
<li><p><strong>PostgreSQL</strong> (hosted on NeonDB) — For storing user data and resume information</p>
</li>
<li><p><strong>NextAuth.js</strong> — Handling authentication with Google, LinkedIn, and Twitter OAuth providers</p>
</li>
<li><p><strong>Amazon S3</strong> — Storing user assets like profile images securely</p>
</li>
<li><p><strong>Vercel</strong> — Hosting the entire application for fast, global delivery</p>
</li>
</ul>
<h2 id="heading-key-features">Key Features</h2>
<h3 id="heading-1-user-authentication">1. User Authentication</h3>
<p>Users can sign up and log in easily using their Google, LinkedIn, or Twitter accounts — thanks to NextAuth.js, which made integrating OAuth smooth and secure.</p>
<h3 id="heading-2-ten-beautiful-resume-templates">2. Ten Beautiful Resume Templates</h3>
<p>The app offers 10 distinct, professionally designed resume templates. Users can select a template that suits their style and industry.</p>
<h3 id="heading-3-dynamic-resume-editor">3. Dynamic Resume Editor</h3>
<p>The editor page lets users fill in their personal details, work experience, education, skills, and more — with live preview so they see changes instantly.</p>
<h3 id="heading-4-pdf-export">4. PDF Export</h3>
<p>Once finished, users can download their resume as a PDF, preserving the chosen template’s formatting perfectly.</p>
<h3 id="heading-5-user-dashboard-and-settings">5. User Dashboard and Settings</h3>
<p>Users have access to a personal dashboard where they can manage resumes, update profile information, and reset their passwords securely.</p>
<h2 id="heading-challenges-and-learnings">Challenges and Learnings</h2>
<h3 id="heading-pdf-generation">PDF Generation</h3>
<p>Ensuring that the resumes print correctly to PDF across different browsers was tricky. Chrome’s print engine behaves differently than others, so I had to experiment with CSS print styles and React-to-PDF libraries to get consistent results.</p>
<h3 id="heading-oauth-integration">OAuth Integration</h3>
<p>Supporting multiple OAuth providers required careful handling of user sessions and callback URLs. NextAuth.js was very helpful, but I had to tweak adapters to fit Prisma and NeonDB.</p>
<h3 id="heading-asset-management">Asset Management</h3>
<p>Uploading and serving user profile images securely was a priority. Using Amazon S3 with signed URLs ensured that images were private and scalable.</p>
<h2 id="heading-final-thoughts">Final Thoughts</h2>
<p>This project has been an incredible learning journey into full-stack development, cloud asset management, and authentication flows. If you’re looking to build your own web apps, I highly recommend exploring Next.js and Prisma — the developer experience is excellent.</p>
<p>Feel free to check out the live demo here: <a target="_blank" href="https://resume-org.vercel.app">https://resume-org.vercel.app</a> and share your feedback or questions!</p>
<hr />
<p><strong>Thanks for reading!</strong><br />— Shubham (SKB)</p>
]]></content:encoded></item></channel></rss>