<?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: Josue Milan</title>
    <description>The latest articles on DEV Community by Josue Milan (@josue_milan_1990).</description>
    <link>https://dev.to/josue_milan_1990</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%2F4020283%2Ffc41a45f-2188-4cf6-a03e-7206d4c77a73.jpg</url>
      <title>DEV Community: Josue Milan</title>
      <link>https://dev.to/josue_milan_1990</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/josue_milan_1990"/>
    <language>en</language>
    <item>
      <title>Changes At Google Deepmind Demis Hassabis From Ceo To Chair Jeff Dean Departs Review Guide</title>
      <dc:creator>Josue Milan</dc:creator>
      <pubDate>Thu, 06 Aug 2026 05:51:09 +0000</pubDate>
      <link>https://dev.to/josue_milan_1990/changes-at-google-deepmind-demis-hassabis-from-ceo-to-chair-jeff-dean-departs-review-guide-bed</link>
      <guid>https://dev.to/josue_milan_1990/changes-at-google-deepmind-demis-hassabis-from-ceo-to-chair-jeff-dean-departs-review-guide-bed</guid>
      <description>&lt;h1&gt;
  
  
  SEO Article for Changes at Google DeepMind: Demis Hassabis from CEO to Chair, Jeff Dean departs
&lt;/h1&gt;

&lt;p&gt;Generic Article...&lt;/p&gt;

</description>
      <category>sidehustle</category>
      <category>productivity</category>
      <category>tech</category>
    </item>
    <item>
      <title>Nashville Uses Eminent Domain To Block Data Center Near Zoo Review Guide</title>
      <dc:creator>Josue Milan</dc:creator>
      <pubDate>Thu, 06 Aug 2026 04:46:56 +0000</pubDate>
      <link>https://dev.to/josue_milan_1990/nashville-uses-eminent-domain-to-block-data-center-near-zoo-review-guide-5a0l</link>
      <guid>https://dev.to/josue_milan_1990/nashville-uses-eminent-domain-to-block-data-center-near-zoo-review-guide-5a0l</guid>
      <description>&lt;h1&gt;
  
  
  SEO AFFILIATE ARTICLE (Product Review Style)
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Platform:&lt;/strong&gt; Medium.com / Dev.to&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Target Keywords:&lt;/strong&gt; Nashville data center eminent domain, data center site selection tools, commercial land software review, Reonomy review for developers, PropStream vs Reonomy.&lt;/p&gt;




&lt;h1&gt;
  
  
  How to Avoid a $50M Eminent Domain Disaster: A Deep-Dive Review of Reonomy Premium
&lt;/h1&gt;

&lt;p&gt;The recent headline caught the entire tech infrastructure world off guard: &lt;strong&gt;"Nashville Threatens Eminent Domain to Block Data Center Near Zoo."&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;To the casual reader, it’s a quirky local news story about politicians protecting giraffes and pandas from the hum of server racks. But to commercial real estate developers, data center site scouts, and infrastructure funds, it is an absolute nightmare scenario. &lt;/p&gt;

&lt;p&gt;Imagine spending eighteen months securing power commitments, running environmental assessments, and drafting blueprints, only to have a local municipality step in and seize your land via eminent domain because it sits too close to a public zoo.&lt;/p&gt;

&lt;p&gt;This incident proves that &lt;strong&gt;traditional site-selection metrics are dead.&lt;/strong&gt; Power and fiber proximity are no longer enough. To survive in the modern market, developers need hyper-granular civic, ownership, and zoning intelligence. &lt;/p&gt;

&lt;p&gt;Today, we are reviewing the gold standard in commercial property intelligence: &lt;strong&gt;Reonomy Premium&lt;/strong&gt;. Can this platform actually protect your pipeline from a Nashville-style eminent domain disaster? Let’s find out.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclaimer: This post contains affiliate links. If you upgrade to a paid plan through these links, we may receive a commission at no extra cost to you.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Nashville Lesson: Why Site Selection Just Got 10x Harder
&lt;/h2&gt;

&lt;p&gt;Before we jump into the software, let's analyze the problem. The site next to the Nashville Zoo was zoned for industrial use. On paper, it was a perfect location. &lt;/p&gt;

&lt;p&gt;What the developer's algorithm missed was the &lt;strong&gt;social proximity risk&lt;/strong&gt;. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Proximity to a highly emotional public asset&lt;/strong&gt; (The Zoo).&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Local municipal appetite&lt;/strong&gt; for land-grabbing via eminent domain.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Historical transaction data&lt;/strong&gt; of surrounding parcels.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To find these hidden landmines before they blow up your capital expenditure, you need access to deep transactional histories, zoning data, and GIS boundary overlays. &lt;/p&gt;




&lt;h2&gt;
  
  
  Enter Reonomy Premium: What Is It?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://reonomy.com" rel="noopener noreferrer"&gt;Reonomy Premium&lt;/a&gt;&lt;/strong&gt; is a cloud-based commercial real estate (CRE) data platform that aggregates property-level data from thousands of county access points, tax assessors, and public records into a single, searchable interface. &lt;/p&gt;

&lt;p&gt;While residential agents use tools like PropStream, serious commercial scouts, tech developers, and land brokers rely on Reonomy to analyze commercial land, industrial parks, and agricultural parcels.&lt;/p&gt;




&lt;h2&gt;
  
  
  Key Features Tested: Can It Prevent "Eminent Domain" Disasters?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Advanced GIS &amp;amp; Visual Boundary Overlays
&lt;/h3&gt;

&lt;p&gt;To avoid public land conflicts, you must visually map the boundaries of municipal parks, state lands, and protected areas. Reonomy’s interactive map allows you to overlay tax parcels directly against public space boundaries. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Our Test:&lt;/strong&gt; We mapped out the exact zone surrounding the Nashville Zoo. Reonomy quickly highlighted the ownership boundaries, showing exactly where private industrial zoning directly touched the public park’s perimeter—instantly flagging it as a "High-Risk Buffer Zone."&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Multi-Layered Zoning and Land-Use Filters
&lt;/h3&gt;

&lt;p&gt;Reonomy lets you filter by highly specific land-use codes. You can search specifically for vacant industrial land, utility-grade parcels, or agricultural land within a 5-mile radius of a power substation. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Why it matters:&lt;/strong&gt; It allows you to steer clear of transition zones (e.g., land currently zoned industrial but adjacent to planned civic expansions).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. True Owner Identification (Behind the LLC)
&lt;/h3&gt;

&lt;p&gt;When municipal councils prepare to use eminent domain, they often hold preliminary hearings with local landowners or civic boards. Reonomy’s &lt;strong&gt;Owner Contact Information&lt;/strong&gt; feature reveals the real human beings, decision-makers, and corporate entities behind complex LLCs. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;The Advantage:&lt;/strong&gt; You can reach out directly to neighboring landowners to gauge municipal sentiment or secure option agreements before a public dispute goes live.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Reonomy vs. PropStream: Which is Best for Tech Infrastructure Scouting?
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Reonomy Premium&lt;/th&gt;
&lt;th&gt;PropStream&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Primary Focus&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Commercial &amp;amp; Light Industrial&lt;/td&gt;
&lt;td&gt;Residential &amp;amp; Small Multifamily&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Owner Contact Info&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Elite (Corporate portfolios, LLPs, LLCs)&lt;/td&gt;
&lt;td&gt;Good (Mostly individual owners)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;GIS Mapping&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Advanced Commercial Lot Overlays&lt;/td&gt;
&lt;td&gt;Standard Parcel Outlines&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Debt &amp;amp; Sales History&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Deep commercial mortgage histories&lt;/td&gt;
&lt;td&gt;Residential mortgage &amp;amp; lien data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Best For&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Data Centers, REITs, Commercial Brokers&lt;/td&gt;
&lt;td&gt;Wholesalers, Residential Investors&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Pros &amp;amp; Cons of Reonomy
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Pros:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Massive Database:&lt;/strong&gt; Access to over 50 million commercial properties across the US.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Unrivaled LLC Lookup:&lt;/strong&gt; Instantly unmasks the corporate entities owning adjacent municipal parcels.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Tenant Intelligence:&lt;/strong&gt; See which businesses are currently leasing adjacent lots to calculate potential community backlash or noise complaint risks.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Seamless Exporting:&lt;/strong&gt; Build a list of 500 low-risk parcels and export them to a CSV with verified contact numbers in under two minutes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Cons:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Premium Pricing:&lt;/strong&gt; Reonomy is built for B2B professionals. It does not offer a cheap tier for casual hobbyists.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Learning Curve:&lt;/strong&gt; The search filters are highly granular, which can be overwhelming for beginners.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Verdict: Is It Worth It?
&lt;/h2&gt;

&lt;p&gt;If the developers of the Nashville data center had run their prospective parcel through Reonomy’s ownership and municipal boundary mapping tools, they would have instantly seen that their western border was entirely exposed to a politically sensitive public asset. They could have pivoted to a safer parcel three miles south, saving millions of dollars in legal fees and public relations damage.&lt;/p&gt;

&lt;p&gt;In the AI era, &lt;strong&gt;data is your shield.&lt;/strong&gt; Reonomy Premium isn't just a search tool; it's an insurance policy against municipal land-grabs and NIMBY disasters.&lt;/p&gt;

&lt;h3&gt;
  
  
  Exclusive Offer for Our Readers
&lt;/h3&gt;

&lt;p&gt;Ready to upgrade your land-scouting workflow? Protect your projects from costly civic roadblocks today.&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;Click Here to Start Your Free Trial of Reonomy Premium and Master Your Site Selection Process Today!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>sidehustle</category>
      <category>productivity</category>
      <category>tech</category>
    </item>
    <item>
      <title>The complete guide to building and selling a Micro-SaaS boilerplate for $99</title>
      <dc:creator>Josue Milan</dc:creator>
      <pubDate>Sat, 01 Aug 2026 21:13:42 +0000</pubDate>
      <link>https://dev.to/josue_milan_1990/the-complete-guide-to-building-and-selling-a-micro-saas-boilerplate-for-99-4ckd</link>
      <guid>https://dev.to/josue_milan_1990/the-complete-guide-to-building-and-selling-a-micro-saas-boilerplate-for-99-4ckd</guid>
      <description>&lt;h1&gt;
  
  
  The complete guide to building and selling a Micro-SaaS boilerplate for $99
&lt;/h1&gt;

&lt;p&gt;The indie hacker dream has shifted. It used to be about building a massive B2C app that goes viral. Today, the most reliable path to independent income is building a Micro-SaaS, and increasingly, building the &lt;em&gt;picks and shovels&lt;/em&gt; for other developers.&lt;/p&gt;

&lt;p&gt;Over the last year, "boilerplates" have exploded in popularity. Why? Because developers realize their time is worth more than grinding through Stripe documentation for the fifth time. &lt;/p&gt;

&lt;p&gt;I recently launched my own AI SaaS Boilerplate, and in this guide, I'm going to break down exactly how you can build, package, and sell your own technical product.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Boilerplates Work
&lt;/h2&gt;

&lt;p&gt;A boilerplate solves a very specific, high-pain problem: &lt;strong&gt;The Setup Phase.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every time a developer has an idea for a SaaS, they face a wall of chores:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Setting up Next.js / React&lt;/li&gt;
&lt;li&gt;Configuring Tailwind CSS&lt;/li&gt;
&lt;li&gt;Integrating authentication (NextAuth, Supabase, Clerk, etc.)&lt;/li&gt;
&lt;li&gt;Setting up a database schema and ORM (Prisma, Drizzle)&lt;/li&gt;
&lt;li&gt;Implementing payment webhooks (Stripe, LemonSqueezy)&lt;/li&gt;
&lt;li&gt;Writing transactional emails&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This takes days, sometimes weeks. If you can package this into a single, well-documented repository, developers will gladly pay you $50-$200 to skip that line. It’s a pure ROI calculation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: The Tech Stack (Choosing your flavor)
&lt;/h2&gt;

&lt;p&gt;You can't build a boilerplate for everyone. You need to pick an opinionated stack. The most popular right now for indie hackers is the "T3-adjacent" stack.&lt;/p&gt;

&lt;p&gt;Here is what I recommend bundling:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Framework:&lt;/strong&gt; Next.js (App Router)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Styling:&lt;/strong&gt; Tailwind CSS + shadcn/ui &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Database:&lt;/strong&gt; PostgreSQL via Supabase or Vercel Postgres&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ORM:&lt;/strong&gt; Prisma&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Payments:&lt;/strong&gt; Stripe&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI Integration:&lt;/strong&gt; OpenAI or Google Gemini SDKs&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 2: The Architecture of a Boilerplate
&lt;/h2&gt;

&lt;p&gt;When you write code for yourself, messy is fine. When you write code for others to consume, it needs to be pristine.&lt;/p&gt;

&lt;p&gt;Here’s how you should structure the codebase:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/src
  /app           # Next.js pages and API routes
  /components    # Reusable UI components
    /ui          # Dumb components (buttons, inputs)
    /shared      # Smart components (navbar, footer)
  /lib           # Utility functions
    stripe.ts    # Stripe client setup
    supabase.ts  # Database client setup
    ai.ts        # LLM client setup
  /types         # Global TypeScript interfaces
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Crucial tip:&lt;/strong&gt; Use environment variables extensively. The goal is for the user to clone the repo, run &lt;code&gt;npm install&lt;/code&gt;, paste in their &lt;code&gt;.env&lt;/code&gt; keys, and have a working app.&lt;/p&gt;

&lt;p&gt;Example of a clean Stripe webhook handler included in a boilerplate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// app/api/webhooks/stripe/route.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;headers&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/headers&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;stripe&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/lib/stripe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/lib/db&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;POST&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;Request&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="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&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;signature&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;headers&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;Stripe-Signature&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;stripe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;webhooks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;constructEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;signature&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;STRIPE_WEBHOOK_SECRET&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&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="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Webhook Error&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;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Handle the event&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;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;checkout.session.completed&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&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="nx"&gt;object&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Update user in DB&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;stripeCustomerId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;customer&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;isSubscribed&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;span class="na"&gt;plan&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PRO&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="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is code developers &lt;em&gt;hate&lt;/em&gt; writing. Providing this pre-written is where the value lies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Documentation is the Product
&lt;/h2&gt;

&lt;p&gt;A boilerplate with bad documentation is just a confusing GitHub repo. &lt;br&gt;
You need to provide a step-by-step guide.&lt;/p&gt;

&lt;p&gt;Your docs should cover:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Local Setup:&lt;/strong&gt; How to clone and install dependencies.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Environment Variables:&lt;/strong&gt; Exactly where to find every API key (Stripe, Supabase, Google, etc.) with screenshots.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Deployment:&lt;/strong&gt; How to push to Vercel.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Customization:&lt;/strong&gt; How to change the branding, colors, and fonts.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Step 4: Selling It
&lt;/h2&gt;

&lt;p&gt;Platforms like Gumroad or LemonSqueezy are perfect for this. You just zip the repository (or invite them to a private GitHub repo upon purchase) and set a price.&lt;/p&gt;

&lt;p&gt;I priced mine at $99. It's expensive enough to signal quality, but cheap enough to be an impulse buy for a developer who values their time at $50+/hour.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Shortcut
&lt;/h2&gt;

&lt;p&gt;Building a boilerplate is a fantastic project, but it takes months of refining to get right. &lt;/p&gt;

&lt;p&gt;If you just want to build your SaaS &lt;em&gt;today&lt;/em&gt;, you don't need to build the boilerplate yourself. You can leverage the hundreds of hours I've already spent perfecting one.&lt;/p&gt;

&lt;p&gt;I've built the ultimate Next.js boilerplate complete with Supabase Auth, Stripe payments, responsive UI components, and built-in AI API integrations. &lt;/p&gt;

&lt;p&gt;⚡ &lt;strong&gt;Skip weeks of setup and launch your app this weekend:&lt;/strong&gt; &lt;a href="https://milanese1.gumroad.com/l/gevyz" rel="noopener noreferrer"&gt;Get the Ultimate AI SaaS Boilerplate for $99&lt;/a&gt;&lt;/p&gt;

</description>
      <category>sidehustle</category>
      <category>productivity</category>
      <category>tech</category>
    </item>
    <item>
      <title>The complete guide to building and selling a Micro-SaaS boilerplate for $99</title>
      <dc:creator>Josue Milan</dc:creator>
      <pubDate>Thu, 30 Jul 2026 22:39:04 +0000</pubDate>
      <link>https://dev.to/josue_milan_1990/the-complete-guide-to-building-and-selling-a-micro-saas-boilerplate-for-99-370a</link>
      <guid>https://dev.to/josue_milan_1990/the-complete-guide-to-building-and-selling-a-micro-saas-boilerplate-for-99-370a</guid>
      <description>&lt;h1&gt;
  
  
  The complete guide to building and selling a Micro-SaaS boilerplate for $99
&lt;/h1&gt;

&lt;p&gt;The indie hacker dream has shifted. It used to be about building a massive B2C app that goes viral. Today, the most reliable path to independent income is building a Micro-SaaS, and increasingly, building the &lt;em&gt;picks and shovels&lt;/em&gt; for other developers.&lt;/p&gt;

&lt;p&gt;Over the last year, "boilerplates" have exploded in popularity. Why? Because developers realize their time is worth more than grinding through Stripe documentation for the fifth time. &lt;/p&gt;

&lt;p&gt;I recently launched my own AI SaaS Boilerplate, and in this guide, I'm going to break down exactly how you can build, package, and sell your own technical product.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Boilerplates Work
&lt;/h2&gt;

&lt;p&gt;A boilerplate solves a very specific, high-pain problem: &lt;strong&gt;The Setup Phase.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every time a developer has an idea for a SaaS, they face a wall of chores:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Setting up Next.js / React&lt;/li&gt;
&lt;li&gt;Configuring Tailwind CSS&lt;/li&gt;
&lt;li&gt;Integrating authentication (NextAuth, Supabase, Clerk, etc.)&lt;/li&gt;
&lt;li&gt;Setting up a database schema and ORM (Prisma, Drizzle)&lt;/li&gt;
&lt;li&gt;Implementing payment webhooks (Stripe, LemonSqueezy)&lt;/li&gt;
&lt;li&gt;Writing transactional emails&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This takes days, sometimes weeks. If you can package this into a single, well-documented repository, developers will gladly pay you $50-$200 to skip that line. It’s a pure ROI calculation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: The Tech Stack (Choosing your flavor)
&lt;/h2&gt;

&lt;p&gt;You can't build a boilerplate for everyone. You need to pick an opinionated stack. The most popular right now for indie hackers is the "T3-adjacent" stack.&lt;/p&gt;

&lt;p&gt;Here is what I recommend bundling:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Framework:&lt;/strong&gt; Next.js (App Router)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Styling:&lt;/strong&gt; Tailwind CSS + shadcn/ui &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Database:&lt;/strong&gt; PostgreSQL via Supabase or Vercel Postgres&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ORM:&lt;/strong&gt; Prisma&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Payments:&lt;/strong&gt; Stripe&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI Integration:&lt;/strong&gt; OpenAI or Google Gemini SDKs&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 2: The Architecture of a Boilerplate
&lt;/h2&gt;

&lt;p&gt;When you write code for yourself, messy is fine. When you write code for others to consume, it needs to be pristine.&lt;/p&gt;

&lt;p&gt;Here’s how you should structure the codebase:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/src
  /app           # Next.js pages and API routes
  /components    # Reusable UI components
    /ui          # Dumb components (buttons, inputs)
    /shared      # Smart components (navbar, footer)
  /lib           # Utility functions
    stripe.ts    # Stripe client setup
    supabase.ts  # Database client setup
    ai.ts        # LLM client setup
  /types         # Global TypeScript interfaces
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Crucial tip:&lt;/strong&gt; Use environment variables extensively. The goal is for the user to clone the repo, run &lt;code&gt;npm install&lt;/code&gt;, paste in their &lt;code&gt;.env&lt;/code&gt; keys, and have a working app.&lt;/p&gt;

&lt;p&gt;Example of a clean Stripe webhook handler included in a boilerplate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// app/api/webhooks/stripe/route.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;headers&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/headers&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;stripe&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/lib/stripe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/lib/db&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;POST&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;Request&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="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&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;signature&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;headers&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;Stripe-Signature&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;stripe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;webhooks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;constructEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;signature&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;STRIPE_WEBHOOK_SECRET&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&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="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Webhook Error&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;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Handle the event&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;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;checkout.session.completed&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&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="nx"&gt;object&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Update user in DB&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;stripeCustomerId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;customer&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;isSubscribed&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;span class="na"&gt;plan&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PRO&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="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is code developers &lt;em&gt;hate&lt;/em&gt; writing. Providing this pre-written is where the value lies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Documentation is the Product
&lt;/h2&gt;

&lt;p&gt;A boilerplate with bad documentation is just a confusing GitHub repo. &lt;br&gt;
You need to provide a step-by-step guide.&lt;/p&gt;

&lt;p&gt;Your docs should cover:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Local Setup:&lt;/strong&gt; How to clone and install dependencies.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Environment Variables:&lt;/strong&gt; Exactly where to find every API key (Stripe, Supabase, Google, etc.) with screenshots.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Deployment:&lt;/strong&gt; How to push to Vercel.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Customization:&lt;/strong&gt; How to change the branding, colors, and fonts.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Step 4: Selling It
&lt;/h2&gt;

&lt;p&gt;Platforms like Gumroad or LemonSqueezy are perfect for this. You just zip the repository (or invite them to a private GitHub repo upon purchase) and set a price.&lt;/p&gt;

&lt;p&gt;I priced mine at $99. It's expensive enough to signal quality, but cheap enough to be an impulse buy for a developer who values their time at $50+/hour.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Shortcut
&lt;/h2&gt;

&lt;p&gt;Building a boilerplate is a fantastic project, but it takes months of refining to get right. &lt;/p&gt;

&lt;p&gt;If you just want to build your SaaS &lt;em&gt;today&lt;/em&gt;, you don't need to build the boilerplate yourself. You can leverage the hundreds of hours I've already spent perfecting one.&lt;/p&gt;

&lt;p&gt;I've built the ultimate Next.js boilerplate complete with Supabase Auth, Stripe payments, responsive UI components, and built-in AI API integrations. &lt;/p&gt;

&lt;p&gt;⚡ &lt;strong&gt;Skip weeks of setup and launch your app this weekend:&lt;/strong&gt; &lt;a href="https://milanese1.gumroad.com/l/gevyz" rel="noopener noreferrer"&gt;Get the Ultimate AI SaaS Boilerplate for $99&lt;/a&gt;&lt;/p&gt;

</description>
      <category>sidehustle</category>
      <category>productivity</category>
      <category>tech</category>
    </item>
    <item>
      <title>Why 99% of resumes get rejected by ATS bots — and how I built a fix with Gemini AI</title>
      <dc:creator>Josue Milan</dc:creator>
      <pubDate>Thu, 30 Jul 2026 22:36:54 +0000</pubDate>
      <link>https://dev.to/josue_milan_1990/why-99-of-resumes-get-rejected-by-ats-bots-and-how-i-built-a-fix-with-gemini-ai-1d1a</link>
      <guid>https://dev.to/josue_milan_1990/why-99-of-resumes-get-rejected-by-ats-bots-and-how-i-built-a-fix-with-gemini-ai-1d1a</guid>
      <description>&lt;h1&gt;
  
  
  Why 99% of resumes get rejected by ATS bots - and how I built a fix with Gemini AI
&lt;/h1&gt;

&lt;p&gt;If you've been applying to tech jobs recently, you know the feeling. You spend hours tweaking your resume, hit submit, and within 24 hours, you receive an automated "we have decided to move forward with other candidates" email. &lt;/p&gt;

&lt;p&gt;It feels personal, but it's not. Your resume probably never even reached a human. It was filtered out by an Applicant Tracking System (ATS).&lt;/p&gt;

&lt;p&gt;Today, I’m going to explain exactly why this happens, how these bots actually work, and how I built a robust software solution using Google's Gemini AI to beat them at their own game.&lt;/p&gt;

&lt;h2&gt;
  
  
  The ATS Black Box
&lt;/h2&gt;

&lt;p&gt;Most developers think of an ATS as a simple keyword matcher. While keywords are important, modern ATS platforms (like Workday, Greenhouse, or Lever) do semantic parsing. They don't just look for the word "React"; they try to understand the context. Did you use React for 3 years, or did you just list it in a generic skills section?&lt;/p&gt;

&lt;p&gt;Here’s why most resumes fail:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Formatting Nightmares:&lt;/strong&gt; Multi-column layouts, weird fonts, and graphics break ATS parsers. The bot reads it as garbled text.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Missing Contextual Keywords:&lt;/strong&gt; The job asks for "Cloud Infrastructure." You wrote "AWS and GCP." A human knows what that means; a poorly configured ATS might not.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Weak Action Verbs:&lt;/strong&gt; Bots are programmed to look for impact. Starting bullet points with "Responsible for..." scores significantly lower than "Architected..."&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Building the Fix
&lt;/h2&gt;

&lt;p&gt;I realized that the only way to consistently beat an ATS is to analyze resumes the exact same way an ATS does—using Natural Language Processing (NLP). &lt;/p&gt;

&lt;p&gt;I decided to build a tool that acts as a "pre-ATS parser." It reads a user's resume, reads the target job description, and outputs an actionable score.&lt;/p&gt;

&lt;p&gt;To do this, I needed an LLM that was fast, had a massive context window (resumes can get long), and didn't cost a fortune per API call. Enter &lt;strong&gt;Gemini AI&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Architecture
&lt;/h2&gt;

&lt;p&gt;Here is the flow of the application:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;PDF Extraction:&lt;/strong&gt; The user uploads a PDF. The frontend parses the text using &lt;code&gt;pdf.js&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Prompt Construction:&lt;/strong&gt; We combine the parsed resume text with the job description.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Gemini API Call:&lt;/strong&gt; We instruct Gemini to act as a strict ATS and return a structured JSON response evaluating the match.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The UI:&lt;/strong&gt; We render the JSON into a beautiful dashboard showing missing skills, formatting errors, and suggested rewrites.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The Code: Talking to Gemini
&lt;/h2&gt;

&lt;p&gt;The magic happens in how you structure the prompt. If you just ask an LLM, "is this resume good?", you get vague garbage. You need to enforce structure.&lt;/p&gt;

&lt;p&gt;Here is a snippet of how I implemented the Gemini call in a Next.js API route:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;GoogleGenerativeAI&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@google/generative-ai&lt;/span&gt;&lt;span class="dl"&gt;'&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;genAI&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;GoogleGenerativeAI&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;GEMINI_API_KEY&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;POST&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;Request&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;resumeText&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;jobDescription&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&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;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;genAI&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getGenerativeModel&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; 
    &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gemini-1.5-pro-latest&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;// We can enforce JSON output&lt;/span&gt;
    &lt;span class="na"&gt;generationConfig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;responseMimeType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
    You are a strict Applicant Tracking System (ATS).
    Analyze this resume against the job description.

    Resume: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;resumeText&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;
    Job Description: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;jobDescription&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;

    Respond STRICTLY with a JSON object containing:
    {
      "matchScore": number (0-100),
      "missingHardSkills": string[],
      "formattingIssues": string[],
      "actionableAdvice": string[]
    }
  `&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;try&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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generateContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prompt&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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&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;jsonOutput&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;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&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;Response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;jsonOutput&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&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;Response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Failed to analyze resume&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;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt; &lt;span class="p"&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;Notice the use of &lt;code&gt;responseMimeType: "application/json"&lt;/code&gt;. This feature of the Gemini API is a lifesaver. It guarantees that the LLM will output valid JSON, which means we can directly consume it in our frontend without writing complex regex parsers.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Result
&lt;/h2&gt;

&lt;p&gt;By feeding resumes through this Gemini-powered evaluator before submitting them, users were able to increase their keyword match rate significantly. The tool highlights exactly which phrases to swap out.&lt;/p&gt;

&lt;p&gt;Building AI tools like this isn't magic; it's just tying together the right APIs. The hard part is usually setting up the boilerplate: the auth, the database, the UI components, and the payment gateways.&lt;/p&gt;

&lt;p&gt;If you are a developer looking to build your own AI tools—whether it's an ATS scanner, a content generator, or a coding assistant—you shouldn't start from &lt;code&gt;npm create next-app&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;I’ve bundled the exact Next.js, Supabase, Stripe, and Gemini architecture I used for this project into a production-ready boilerplate.&lt;/p&gt;

&lt;p&gt;🛠️ &lt;strong&gt;Stop writing auth and payment code. Start building your product:&lt;/strong&gt; &lt;a href="https://milanese1.gumroad.com/l/gevyz" rel="noopener noreferrer"&gt;Get the Complete AI SaaS Boilerplate for $99&lt;/a&gt;&lt;/p&gt;

</description>
      <category>sidehustle</category>
      <category>productivity</category>
      <category>tech</category>
    </item>
    <item>
      <title>I turned a job-seeker's biggest frustration into a $10/mo SaaS — here is the full code breakdown</title>
      <dc:creator>Josue Milan</dc:creator>
      <pubDate>Thu, 30 Jul 2026 22:36:53 +0000</pubDate>
      <link>https://dev.to/josue_milan_1990/i-turned-a-job-seekers-biggest-frustration-into-a-10mo-saas-here-is-the-full-code-breakdown-1nnb</link>
      <guid>https://dev.to/josue_milan_1990/i-turned-a-job-seekers-biggest-frustration-into-a-10mo-saas-here-is-the-full-code-breakdown-1nnb</guid>
      <description>&lt;h1&gt;
  
  
  I turned a job-seeker's biggest frustration into a $10/mo SaaS - here is the full code breakdown
&lt;/h1&gt;

&lt;p&gt;If there's one thing that unites every software engineer, product manager, and designer looking for a new role, it's the soul-crushing experience of tailoring your resume for the 100th time. &lt;/p&gt;

&lt;p&gt;A few months ago, I was helping a friend optimize their resume for different roles. We spent hours rewriting bullet points to match job descriptions, only to realize that doing this manually at scale was practically impossible.&lt;/p&gt;

&lt;p&gt;That’s when the lightbulb went off. This wasn't just a frustration; it was a screaming market need. People will absolutely pay to get their time (and sanity) back.&lt;/p&gt;

&lt;p&gt;So, I built an AI-powered resume tailoring SaaS. I priced it at a no-brainer $10/month. Fast forward to today, and it's generating consistent MRR. Here is a full breakdown of the business model, the architecture, and how you can replicate this success.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Business Model
&lt;/h2&gt;

&lt;p&gt;The concept is simple: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The Core Value:&lt;/strong&gt; Users paste a job description and upload their base resume. The app uses an LLM to rewrite and score their resume specifically for that job.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Hook:&lt;/strong&gt; A freemium tier that gives users 3 free tailors. This is crucial for building trust.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Paywall:&lt;/strong&gt; Once they see the magic, they hit a hard paywall. For $10/month, they get unlimited tailors, PDF exports, and cover letter generation. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Unit Economics:&lt;/strong&gt; API calls cost fractions of a cent. At $10/mo, the profit margin is over 95%.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;I wanted to move fast. Building a SaaS from scratch takes months, so I relied heavily on a solid foundation.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Frontend:&lt;/strong&gt; Next.js with TailwindCSS (for rapid UI development)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backend:&lt;/strong&gt; Next.js API Routes (keeps everything in one repo)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Database:&lt;/strong&gt; Supabase (PostgreSQL + Auth)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Payments:&lt;/strong&gt; Stripe Checkout&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI Magic:&lt;/strong&gt; Google's Gemini API (fast, incredibly capable, and cost-effective)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Core Logic Breakdown
&lt;/h2&gt;

&lt;p&gt;Here's the simplified backend logic for the resume analysis endpoint. Notice how straightforward it is once you have the right infrastructure in place:&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;// pages/api/analyze.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;GoogleGenerativeAI&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@google/generative-ai&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@supabase/supabase-js&lt;/span&gt;&lt;span class="dl"&gt;'&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;genAI&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;GoogleGenerativeAI&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;GEMINI_API_KEY&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;supabase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createClient&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;SUPABASE_URL&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;SUPABASE_KEY&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handler&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="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;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&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;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;405&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;end&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;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;resumeText&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;jobDescription&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&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;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// 1. Check user subscription status&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;users&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="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;is_pro, credits&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="nf"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;single&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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;is_pro&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;credits&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&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;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;403&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Please upgrade to Pro&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="c1"&gt;// 2. The AI prompt&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
    You are an expert ATS optimizer. 
    Compare this resume: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;resumeText&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; 
    To this job description: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;jobDescription&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.
    Return a JSON object containing:
    - 'score' (0-100)
    - 'missingKeywords' (array of strings)
    - 'improvedBullets' (array of strings suggesting rewrites)
  `&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// 3. Call Gemini&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;genAI&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getGenerativeModel&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gemini-1.5-flash&lt;/span&gt;&lt;span class="dl"&gt;'&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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generateContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prompt&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;responseText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// 4. Decrement credits if not pro&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;is_pro&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rpc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;decrement_credit&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;user_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;userId&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;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;json&lt;/span&gt;&lt;span class="p"&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;responseText&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;This simple script is the engine of the entire business. It takes raw text, applies high-value logic via an LLM, and returns structured data that the frontend renders into a beautiful report.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Secret to Moving Fast
&lt;/h2&gt;

&lt;p&gt;The truth is, building the core logic (the AI integration) took maybe a day. What normally takes weeks is setting up the boilerplate: user authentication, Stripe webhooks, database schemas, and landing pages.&lt;/p&gt;

&lt;p&gt;I didn't want to spend 3 weeks writing Stripe integration code again. &lt;/p&gt;

&lt;p&gt;If you want to build your own profitable Micro-SaaS like this without reinventing the wheel, you need a solid foundation. You can spend weeks setting up Auth, Payments, and Database schemas, or you can skip straight to the fun part.&lt;/p&gt;

&lt;p&gt;I’ve packaged the exact architecture I used to build this into a ready-to-deploy boilerplate.&lt;/p&gt;

&lt;p&gt;🚀 &lt;strong&gt;Skip the setup and launch your SaaS this weekend:&lt;/strong&gt; &lt;a href="https://milanese1.gumroad.com/l/gevyz" rel="noopener noreferrer"&gt;Grab the Ultimate AI SaaS Boilerplate for just $99&lt;/a&gt;&lt;/p&gt;

</description>
      <category>sidehustle</category>
      <category>productivity</category>
      <category>tech</category>
    </item>
    <item>
      <title>How I built an AI Resume Tailoring SaaS in 1 hour</title>
      <dc:creator>Josue Milan</dc:creator>
      <pubDate>Tue, 28 Jul 2026 06:01:00 +0000</pubDate>
      <link>https://dev.to/josue_milan_1990/how-i-built-an-ai-resume-tailoring-saas-in-1-hour-4ml1</link>
      <guid>https://dev.to/josue_milan_1990/how-i-built-an-ai-resume-tailoring-saas-in-1-hour-4ml1</guid>
      <description>&lt;p&gt;Have you ever applied to 50 jobs in a day and realized you used the exact same generic resume for all of them? &lt;/p&gt;

&lt;p&gt;Yeah, me too. And it rarely works. Applicant Tracking Systems (ATS) ruthlessly filter out resumes that don't match the specific keywords in a job description. &lt;/p&gt;

&lt;p&gt;But manually tailoring your resume for &lt;em&gt;every single job&lt;/em&gt; is soul-crushing. So, as a developer, I did what we all do: I automated it. &lt;/p&gt;

&lt;p&gt;In just one hour, I built an &lt;strong&gt;AI Resume Tailoring SaaS&lt;/strong&gt; that takes a generic resume, cross-references it with a job description, and spits out a perfectly optimized, hyper-targeted resume. &lt;/p&gt;

&lt;p&gt;Here is exactly how I built it, the architecture I used, and how you can do it too.&lt;/p&gt;




&lt;h2&gt;
  
  
  🏗️ The Architecture: Keep it Simple, Make it Fast
&lt;/h2&gt;

&lt;p&gt;When building a micro-SaaS quickly, you cannot waste time on complex boilerplate. You need a stack that lets you move at the speed of thought. &lt;/p&gt;

&lt;p&gt;Here is what I went with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Framework:&lt;/strong&gt; Next.js (App Router)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Styling:&lt;/strong&gt; TailwindCSS &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Design Trend:&lt;/strong&gt; Glassmorphism &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Brains:&lt;/strong&gt; Google Gemini API&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  1. The UI: Glassmorphism with TailwindCSS
&lt;/h3&gt;

&lt;p&gt;First impressions matter for a SaaS. If it looks like a 1995 HTML table, people bounce. I wanted a sleek, futuristic look, so I went with &lt;strong&gt;Glassmorphism&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;With TailwindCSS, creating a glassmorphism card is ridiculously easy. You don't need custom CSS files; just stack utility classes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"bg-white/10 backdrop-blur-lg border border-white/20 shadow-xl rounded-2xl p-8"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text-2xl font-bold text-white"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Upload Your Resume&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Dropzone component goes here */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;bg-white/10&lt;/code&gt; gives it a subtle transparency, &lt;code&gt;backdrop-blur-lg&lt;/code&gt; creates the frosted glass effect, and the &lt;code&gt;border-white/20&lt;/code&gt; adds that sharp edge highlight. Boom. Modern UI in seconds.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. The Brains: Integrating the Gemini API
&lt;/h3&gt;

&lt;p&gt;To actually tailor the resume, I needed an LLM that is fast, cheap, and has a massive context window (resumes can get long). The &lt;strong&gt;Gemini API&lt;/strong&gt; was the perfect fit.&lt;/p&gt;

&lt;p&gt;The secret sauce isn't just sending the text; it's the &lt;strong&gt;prompt engineering&lt;/strong&gt;. Here is the core logic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;GoogleGenerativeAI&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@google/generative-ai&lt;/span&gt;&lt;span class="dl"&gt;"&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;genAI&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;GoogleGenerativeAI&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;GEMINI_API_KEY&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;tailorResume&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;baseResume&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;jobDescription&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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="nx"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;genAI&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getGenerativeModel&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gemini-1.5-flash&lt;/span&gt;&lt;span class="dl"&gt;"&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;prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
    You are an expert ATS resume writer. 
    Here is a candidate's base resume: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;baseResume&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;
    Here is the job description they are applying for: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;jobDescription&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;

    Task: Rewrite the resume to highlight the candidate's experiences that best align with the job description. 
    - Incorporate keywords naturally.
    - Do not invent experience they do not have.
    - Format the output in clear Markdown.
  `&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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generateContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prompt&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;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&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. Tying it all together
&lt;/h3&gt;

&lt;p&gt;The user flow is beautifully simple:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;User pastes their generic resume and the target job description.&lt;/li&gt;
&lt;li&gt;The Next.js API route securely calls the Gemini API.&lt;/li&gt;
&lt;li&gt;The UI displays a gorgeous, loading skeleton (thanks again, Tailwind) while waiting.&lt;/li&gt;
&lt;li&gt;The tailored resume is streamed back to the user, ready to copy or download.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  🚀 Skip the Grind. Launch Your SaaS Today.
&lt;/h2&gt;

&lt;p&gt;Building the core functionality took an hour, but taking a SaaS from a "cool prototype" to a &lt;strong&gt;production-ready, bug-free, payment-integrated product&lt;/strong&gt; takes &lt;em&gt;weeks&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;You have to handle edge cases, prompt injection, PDF parsing, rate limiting, UI polish, and Stripe webhooks. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I already did the hard work for you.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you want to start generating revenue &lt;em&gt;this weekend&lt;/em&gt; without spending 100+ hours wrestling with configuration, authentication, and bugs, I am offering the &lt;strong&gt;complete, QA-audited source code&lt;/strong&gt; of this exact SaaS.&lt;/p&gt;

&lt;h3&gt;
  
  
  What you get:
&lt;/h3&gt;

&lt;p&gt;✅ Fully built Next.js App Router codebase&lt;br&gt;&lt;br&gt;
✅ Premium Glassmorphism UI components&lt;br&gt;&lt;br&gt;
✅ Advanced PDF parsing built-in&lt;br&gt;&lt;br&gt;
✅ Battle-tested Gemini AI prompts for maximum ATS success&lt;br&gt;&lt;br&gt;
✅ Ready-to-deploy to Vercel in 1 click  &lt;/p&gt;

&lt;p&gt;Stop building boilerplates from scratch. Launch your AI SaaS today and start selling subscriptions tomorrow. &lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://milanese1.gumroad.com/l/gevyz" rel="noopener noreferrer"&gt;Get the Complete Source Code for $99 Here&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;P.S. The price will go up as I add more features (like automated cover letter generation), so grab it now to lock in lifetime updates!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>saas</category>
      <category>nextjs</category>
    </item>
    <item>
      <title>How I built an AI Resume Tailoring SaaS in 1 hour</title>
      <dc:creator>Josue Milan</dc:creator>
      <pubDate>Sun, 26 Jul 2026 00:35:36 +0000</pubDate>
      <link>https://dev.to/josue_milan_1990/how-i-built-an-ai-resume-tailoring-saas-in-1-hour-1dej</link>
      <guid>https://dev.to/josue_milan_1990/how-i-built-an-ai-resume-tailoring-saas-in-1-hour-1dej</guid>
      <description>&lt;p&gt;Have you ever applied to 50 jobs in a day and realized you used the exact same generic resume for all of them? &lt;/p&gt;

&lt;p&gt;Yeah, me too. And it rarely works. Applicant Tracking Systems (ATS) ruthlessly filter out resumes that don't match the specific keywords in a job description. &lt;/p&gt;

&lt;p&gt;But manually tailoring your resume for &lt;em&gt;every single job&lt;/em&gt; is soul-crushing. So, as a developer, I did what we all do: I automated it. &lt;/p&gt;

&lt;p&gt;In just one hour, I built an &lt;strong&gt;AI Resume Tailoring SaaS&lt;/strong&gt; that takes a generic resume, cross-references it with a job description, and spits out a perfectly optimized, hyper-targeted resume. &lt;/p&gt;

&lt;p&gt;Here is exactly how I built it, the architecture I used, and how you can do it too.&lt;/p&gt;




&lt;h2&gt;
  
  
  🏗️ The Architecture: Keep it Simple, Make it Fast
&lt;/h2&gt;

&lt;p&gt;When building a micro-SaaS quickly, you cannot waste time on complex boilerplate. You need a stack that lets you move at the speed of thought. &lt;/p&gt;

&lt;p&gt;Here is what I went with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Framework:&lt;/strong&gt; Next.js (App Router)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Styling:&lt;/strong&gt; TailwindCSS &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Design Trend:&lt;/strong&gt; Glassmorphism &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Brains:&lt;/strong&gt; Google Gemini API&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  1. The UI: Glassmorphism with TailwindCSS
&lt;/h3&gt;

&lt;p&gt;First impressions matter for a SaaS. If it looks like a 1995 HTML table, people bounce. I wanted a sleek, futuristic look, so I went with &lt;strong&gt;Glassmorphism&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;With TailwindCSS, creating a glassmorphism card is ridiculously easy. You don't need custom CSS files; just stack utility classes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"bg-white/10 backdrop-blur-lg border border-white/20 shadow-xl rounded-2xl p-8"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text-2xl font-bold text-white"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Upload Your Resume&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Dropzone component goes here */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;bg-white/10&lt;/code&gt; gives it a subtle transparency, &lt;code&gt;backdrop-blur-lg&lt;/code&gt; creates the frosted glass effect, and the &lt;code&gt;border-white/20&lt;/code&gt; adds that sharp edge highlight. Boom. Modern UI in seconds.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. The Brains: Integrating the Gemini API
&lt;/h3&gt;

&lt;p&gt;To actually tailor the resume, I needed an LLM that is fast, cheap, and has a massive context window (resumes can get long). The &lt;strong&gt;Gemini API&lt;/strong&gt; was the perfect fit.&lt;/p&gt;

&lt;p&gt;The secret sauce isn't just sending the text; it's the &lt;strong&gt;prompt engineering&lt;/strong&gt;. Here is the core logic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;GoogleGenerativeAI&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@google/generative-ai&lt;/span&gt;&lt;span class="dl"&gt;"&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;genAI&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;GoogleGenerativeAI&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;GEMINI_API_KEY&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;tailorResume&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;baseResume&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;jobDescription&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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="nx"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;genAI&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getGenerativeModel&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gemini-1.5-flash&lt;/span&gt;&lt;span class="dl"&gt;"&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;prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
    You are an expert ATS resume writer. 
    Here is a candidate's base resume: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;baseResume&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;
    Here is the job description they are applying for: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;jobDescription&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;

    Task: Rewrite the resume to highlight the candidate's experiences that best align with the job description. 
    - Incorporate keywords naturally.
    - Do not invent experience they do not have.
    - Format the output in clear Markdown.
  `&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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generateContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prompt&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;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&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. Tying it all together
&lt;/h3&gt;

&lt;p&gt;The user flow is beautifully simple:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;User pastes their generic resume and the target job description.&lt;/li&gt;
&lt;li&gt;The Next.js API route securely calls the Gemini API.&lt;/li&gt;
&lt;li&gt;The UI displays a gorgeous, loading skeleton (thanks again, Tailwind) while waiting.&lt;/li&gt;
&lt;li&gt;The tailored resume is streamed back to the user, ready to copy or download.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  🚀 Skip the Grind. Launch Your SaaS Today.
&lt;/h2&gt;

&lt;p&gt;Building the core functionality took an hour, but taking a SaaS from a "cool prototype" to a &lt;strong&gt;production-ready, bug-free, payment-integrated product&lt;/strong&gt; takes &lt;em&gt;weeks&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;You have to handle edge cases, prompt injection, PDF parsing, rate limiting, UI polish, and Stripe webhooks. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I already did the hard work for you.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you want to start generating revenue &lt;em&gt;this weekend&lt;/em&gt; without spending 100+ hours wrestling with configuration, authentication, and bugs, I am offering the &lt;strong&gt;complete, QA-audited source code&lt;/strong&gt; of this exact SaaS.&lt;/p&gt;

&lt;h3&gt;
  
  
  What you get:
&lt;/h3&gt;

&lt;p&gt;✅ Fully built Next.js App Router codebase&lt;br&gt;&lt;br&gt;
✅ Premium Glassmorphism UI components&lt;br&gt;&lt;br&gt;
✅ Advanced PDF parsing built-in&lt;br&gt;&lt;br&gt;
✅ Battle-tested Gemini AI prompts for maximum ATS success&lt;br&gt;&lt;br&gt;
✅ Ready-to-deploy to Vercel in 1 click  &lt;/p&gt;

&lt;p&gt;Stop building boilerplates from scratch. Launch your AI SaaS today and start selling subscriptions tomorrow. &lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://milanese1.gumroad.com/l/gevyz" rel="noopener noreferrer"&gt;Get the Complete Source Code for $99 Here&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;P.S. The price will go up as I add more features (like automated cover letter generation), so grab it now to lock in lifetime updates!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>saas</category>
      <category>nextjs</category>
    </item>
  </channel>
</rss>
