<?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>Forem: Paul ROW</title>
    <description>The latest articles on Forem by Paul ROW (@paul_row226).</description>
    <link>https://forem.com/paul_row226</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3620765%2F0a5c5f8f-367e-47c0-841a-118ba34194de.png</url>
      <title>Forem: Paul ROW</title>
      <link>https://forem.com/paul_row226</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/paul_row226"/>
    <language>en</language>
    <item>
      <title>How I Built a Self-Feeding SEO Engine with GPT-4o Vision + Next.js 15</title>
      <dc:creator>Paul ROW</dc:creator>
      <pubDate>Fri, 21 Nov 2025 04:41:20 +0000</pubDate>
      <link>https://forem.com/paul_row226/how-i-built-a-self-feeding-seo-engine-with-gpt-4o-vision-nextjs-15-55n5</link>
      <guid>https://forem.com/paul_row226/how-i-built-a-self-feeding-seo-engine-with-gpt-4o-vision-nextjs-15-55n5</guid>
      <description>&lt;p&gt;Two weeks ago, I launched an ai tattoo generator called TattooRed. Today, I have 200 pages generated and 15 indexed by Google. But here's the interesting part: &lt;strong&gt;users generate the content, GPT-4o Vision enriches it, and Next.js 15 serves it—automatically.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The architecture is designed to scale from 0 to 100K+ pages at $0.006 per page. Here's exactly how it works—including the disasters I didn't anticipate.&lt;/p&gt;




&lt;h2&gt;
  
  
  🎯 The Problem: 135K Monthly Searches I Couldn't Cover Manually
&lt;/h2&gt;

&lt;p&gt;I started building an &lt;a href="https://tattoored.com" rel="noopener noreferrer"&gt;ai tattoo generator&lt;/a&gt;. The obvious keyword was "ai tattoo generator" (22K monthly searches). But then I discovered &lt;strong&gt;"tattoo ideas"&lt;/strong&gt; gets &lt;strong&gt;135K monthly searches&lt;/strong&gt; with similar difficulty (56% vs 50%).&lt;/p&gt;

&lt;p&gt;The opportunity was massive. But here's the challenge:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do you create 10,000+ unique, SEO-optimized pages for long-tail keywords like:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"minimalist lion tattoo ideas"&lt;/li&gt;
&lt;li&gt;"watercolor phoenix back tattoo"&lt;/li&gt;
&lt;li&gt;"geometric dragon sleeve for men"&lt;/li&gt;
&lt;li&gt;"small butterfly ankle tattoo for women"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Manual content creation? Impossible. Hiring writers? $50-100 per article = $500K+ for 10K pages.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The solution:&lt;/strong&gt; Turn user creativity into SEO content automatically.&lt;/p&gt;




&lt;h2&gt;
  
  
  🏗️ The Architecture: User Content → AI Analysis → SEO Pages
&lt;/h2&gt;

&lt;p&gt;Here's how the system works:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. User Generates a Tattoo
&lt;/h3&gt;

&lt;p&gt;Users describe their tattoo idea (e.g., "phoenix rising from ashes on my back"). The system:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sends the prompt to ModelsLab's Flux API&lt;/li&gt;
&lt;li&gt;Generates a professional tattoo design (white background, no body parts)&lt;/li&gt;
&lt;li&gt;Returns the image in ~15 seconds&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cost: &lt;strong&gt;$0.0047 per image&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Auto-Publish Flow (Free Users)
&lt;/h3&gt;

&lt;p&gt;Free users get their tattoos published automatically to the &lt;a href="https://tattoored.com/tattoo-ideas" rel="noopener noreferrer"&gt;tattoo ideas&lt;/a&gt; gallery. This is the exchange: free generation in return for SEO content contribution.&lt;/p&gt;

&lt;p&gt;When published, the system:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Uploads image to Supabase Storage&lt;/li&gt;
&lt;li&gt;Sends image + user prompt to GPT-4o-mini Vision&lt;/li&gt;
&lt;li&gt;Receives structured SEO content back&lt;/li&gt;
&lt;li&gt;Creates a new Next.js page automatically&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. GPT-4o Vision Analyzes &amp;amp; Generates Content
&lt;/h3&gt;

&lt;p&gt;This is where the magic happens. Here's a simplified version of the API call:&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;// lib/openai-seo-generator.ts&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;analyzeTattooAndGenerateSEO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;imageUrl&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;userPrompt&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;existingCategories&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="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;openai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&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;gpt-4o-mini&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;messages&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="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;system&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`You are an expert tattoo analyst and SEO content writer.`&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;content&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="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
            &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`User prompt: "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;userPrompt&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"

            Return JSON with SEO-optimized content including:
            title, meta description, 500+ word analysis, categories, etc.`&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt; 
            &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;image_url&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
            &lt;span class="na"&gt;image_url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;imageUrl&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="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;response_format&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;json_object&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="k"&gt;return&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="nx"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&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;Cost: &lt;strong&gt;$0.0015 per analysis&lt;/strong&gt; (GPT-4o-mini Vision is 10x cheaper than GPT-4o)&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Next.js 15 Creates Pages Automatically
&lt;/h3&gt;

&lt;p&gt;The returned data creates a new page at &lt;code&gt;/tattoo-ideas/[slug]&lt;/code&gt;:&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/tattoo-ideas/[slug]/page.tsx&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;generateMetadata&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;Props&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;tattoo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getTattooBySlug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;tattoo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;seo_title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;tattoo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;seo_description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;openGraph&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;tattoo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;seo_title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;images&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;tattoo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;image_url&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="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// ISR: Revalidate every hour&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;revalidate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3600&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;💡 &lt;em&gt;Side note: I built this with Claude Code as my coding assistant. The architecture decisions are mine, but Claude helped me write cleaner TypeScript and avoid Next.js pitfalls.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Multi-Category Magic
&lt;/h3&gt;

&lt;p&gt;Each tattoo automatically appears in &lt;strong&gt;multiple category pages&lt;/strong&gt;. A "phoenix rising back tattoo" shows up in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/tattoo-ideas/category/animals&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/tattoo-ideas/category/birds&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/tattoo-ideas/category/mythology&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/tattoo-ideas/category/unisex/animals&lt;/code&gt; (combined)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;One user generation = 5-10 SEO entry points.&lt;/strong&gt; This is the multiplier effect.&lt;/p&gt;




&lt;h2&gt;
  
  
  💰 The Economics: Infinite Scale at $0.006 Per Page
&lt;/h2&gt;

&lt;p&gt;Let's break down the cost per generated SEO page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Image generation (Flux):        $0.0047
GPT-4o-mini Vision analysis:    $0.0015
Supabase storage:               $0.0001
-----------------------------------------
Total per page:                 $0.0063
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;At scale:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1,000 pages = $6.30&lt;/li&gt;
&lt;li&gt;10,000 pages = $63&lt;/li&gt;
&lt;li&gt;100,000 pages = $630&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Compare to traditional content:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Freelance writers: $50-100/article&lt;/li&gt;
&lt;li&gt;Content agencies: $200+/article&lt;/li&gt;
&lt;li&gt;10,000 articles = $500K - $2M&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;ROI calculation:&lt;/strong&gt;&lt;br&gt;
If I get 100 paying users at $13.95/month = $1,395 MRR, that covers &lt;strong&gt;221,000 generated pages&lt;/strong&gt;. The economics work at any scale.&lt;/p&gt;


&lt;h2&gt;
  
  
  😱 The "Oh Shit" Moment (aka What Could Go Wrong)
&lt;/h2&gt;

&lt;p&gt;So there I was, 2 AM, super proud of my creation. System running smoothly. Users generating tattoos. SEO content flowing like a river.&lt;/p&gt;

&lt;p&gt;I went to bed feeling like a genius.&lt;/p&gt;

&lt;p&gt;Then, 10 minutes later, lying in the dark, the thoughts started:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"Wait... what if OpenAI's API goes down?"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"What if I run out of credits and don't notice?"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"What if the background process fails silently and I have 1,000 orphaned tattoos with no SEO content?"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I opened my laptop. Checked the database. &lt;/p&gt;

&lt;p&gt;Yep. &lt;strong&gt;37 orphaned tattoos.&lt;/strong&gt; Published images, but the GPT-4o enrichment process had failed silently. No SEO content. No categories. Just... floating in the void.&lt;/p&gt;
&lt;h3&gt;
  
  
  The Problem: Silent Failures
&lt;/h3&gt;

&lt;p&gt;Here's what was happening:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;User generates tattoo ✅&lt;/li&gt;
&lt;li&gt;Image uploads to Supabase ✅&lt;/li&gt;
&lt;li&gt;Tattoo appears in gallery ✅&lt;/li&gt;
&lt;li&gt;Background job triggers to generate SEO content... ❌ (fails silently)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Why it failed:&lt;/strong&gt;&lt;br&gt;
At first, I blamed the usual suspects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OpenAI API timeout&lt;/li&gt;
&lt;li&gt;Rate limits&lt;/li&gt;
&lt;li&gt;Network hiccups&lt;/li&gt;
&lt;li&gt;Low credits&lt;/li&gt;
&lt;li&gt;A process crash&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But the real issue was something different.&lt;br&gt;
&lt;strong&gt;Everything worked perfectly locally… but failed silently once deployed on Vercel.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Locally, my enrichment function ran synchronously:&lt;br&gt;
I sent the GPT-4o-mini Vision request → waited for the response → stored the SEO content.&lt;br&gt;
No queue, no background jobs, no race conditions.&lt;/p&gt;

&lt;p&gt;But on Vercel, the story changed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Vercel serverless functions have strict execution time limits&lt;/li&gt;
&lt;li&gt;After a few seconds, the function gets hard-killed&lt;/li&gt;
&lt;li&gt;No error is thrown back into your app&lt;/li&gt;
&lt;li&gt;No logs unless you dig deep&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The tattoo gets created… but the enrichment never finishes&lt;/p&gt;

&lt;p&gt;This leads to the weirdest bug:&lt;br&gt;
Everything looks successful from the user’s perspective, but the SEO content is missing.&lt;/p&gt;

&lt;p&gt;I also tried a “fire-and-forget” strategy (trigger enrichment and return immediately), but serverless environments don’t guarantee the background execution will complete—so enrichment jobs were still randomly failing.&lt;/p&gt;

&lt;p&gt;In other words:&lt;/p&gt;

&lt;p&gt;👉 My code wasn’t the problem — the serverless runtime model was.&lt;/p&gt;

&lt;p&gt;The tattoos existed, but they were &lt;strong&gt;SEO zombies&lt;/strong&gt;—alive but without the content that makes them discoverable.&lt;/p&gt;
&lt;h3&gt;
  
  
  The Solution: The "Orphan Tattoo Recovery System"
&lt;/h3&gt;

&lt;p&gt;I built an admin panel with a simple but powerful feature:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"Check for Orphan Tattoos" button&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here's what it does:&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/admin/pending-tattoos/route.ts (simplified)&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;GET&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Find tattoos that are published but missing SEO content&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;orphanTattoos&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;tattoos&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;*&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="k"&gt;is&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;seo_content&lt;/span&gt;&lt;span class="dl"&gt;'&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="c1"&gt;// No SEO content yet&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;published&lt;/span&gt;&lt;span class="dl"&gt;'&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="c1"&gt;// But already published&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;created_at&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;ascending&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;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;orphans&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;orphanTattoos&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="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;orphanTattoos&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;length&lt;/span&gt; 
  &lt;span class="p"&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;request&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;tattooIds&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;request&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="c1"&gt;// Process orphans one by one&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="k"&gt;for &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;id&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;tattooIds&lt;/span&gt;&lt;span class="p"&gt;)&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;tattoo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getTattooById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="c1"&gt;// Retry SEO generation&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;seoContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;analyzeTattooAndGenerateSEO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;tattoo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;image_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;tattoo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user_prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;existingCategories&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="c1"&gt;// Update tattoo with SEO content&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;tattoos&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;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="na"&gt;seo_title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;seoContent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;seo_description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;seoContent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta_description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;seoContent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="c1"&gt;// ... other fields&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;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;id&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;success&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="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="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;id&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;failed&lt;/span&gt;&lt;span class="dl"&gt;'&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="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&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="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;processed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;results&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;&lt;strong&gt;In the admin panel:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Orphan Tattoos Detected: 37

[Check for Orphans] 

┌─────────────────────────────────────────┐
│ phoenix-back-a1b2c3                    │
│ Created: 2 hours ago                   │
│ Status: Missing SEO content            │
│ [Process Now]                          │
└─────────────────────────────────────────┘

┌─────────────────────────────────────────┐
│ dragon-sleeve-d4e5f6                   │
│ Created: 5 hours ago                   │
│ Status: Missing SEO content            │
│ [Process Now]                          │
└─────────────────────────────────────────┘

[Process All (37 tattoos)]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Click the button. Boom. All 37 orphans get their SEO content in ~2 minutes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why this works:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Manual recovery when automation fails&lt;/li&gt;
&lt;li&gt;✅ Retry logic for failed API calls&lt;/li&gt;
&lt;li&gt;✅ Visual confirmation that everything is caught up&lt;/li&gt;
&lt;li&gt;✅ Peace of mind (I can sleep now)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Bonus feature I added:&lt;/strong&gt;&lt;br&gt;
Daily cron job that checks for orphans automatically and sends me a notification:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;🚨 Found 12 orphan tattoos from the last 24 hours
👉 Check admin panel: tattoored.com/admin/tattoos
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  📊 Early Results &amp;amp; Lessons Learned (2 Weeks In)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Current status:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ 200 pages generated&lt;/li&gt;
&lt;li&gt;✅ 15 pages indexed by Google&lt;/li&gt;
&lt;li&gt;✅ Average content length: 520 words&lt;/li&gt;
&lt;li&gt;✅ Generation time: &amp;lt;15 seconds per page&lt;/li&gt;
&lt;li&gt;✅ Zero orphaned tattoos (thanks to recovery system)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What's working:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;User prompts are natural long-tail keywords&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User: "minimalist geometric lion with sunset background"&lt;/li&gt;
&lt;li&gt;Auto-targets: "minimalist lion tattoo", "geometric lion", "sunset tattoo ideas"&lt;/li&gt;
&lt;li&gt;No keyword research needed—users do it for me&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;GPT-4o-mini Vision quality is excellent&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;90% of content needs zero editing&lt;/li&gt;
&lt;li&gt;Understands tattoo culture (placement, style, symbolism)&lt;/li&gt;
&lt;li&gt;10x cheaper than GPT-4o ($0.0015 vs $0.015)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The orphan recovery system is essential&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Caught 37 failures in the first week&lt;/li&gt;
&lt;li&gt;Now runs as daily cron + manual check&lt;/li&gt;
&lt;li&gt;Converts "oh shit" moments into "handled"&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;What I'm still figuring out:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Indexing speed varies wildly&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Some pages indexed in 24h, others take 7+ days&lt;/li&gt;
&lt;li&gt;Testing XML sitemap optimization&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Category page optimization&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Auto-generated intro content needs improvement&lt;/li&gt;
&lt;li&gt;Testing different layouts for gallery grids&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  🚀 What's Next: Scaling to 10K Pages
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Short-term (next 30 days):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reach 1,000 generated pages&lt;/li&gt;
&lt;li&gt;Target 100+ indexed pages&lt;/li&gt;
&lt;li&gt;Track first keyword rankings&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Mid-term (3 months):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Scale to 10,000 pages&lt;/li&gt;
&lt;li&gt;Monitor conversion: organic traffic → free users → paid users&lt;/li&gt;
&lt;li&gt;Add A/B testing for content formats&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Long-term (6+ months):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;50K+ pages (depending on user growth)&lt;/li&gt;
&lt;li&gt;Multi-language support (Spanish, Portuguese, French)&lt;/li&gt;
&lt;li&gt;Artist marketplace integration&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🏗️ Building in Public: BoomPath + TattooRed
&lt;/h2&gt;

&lt;p&gt;I'm documenting this entire journey on Twitter (&lt;a href="https://x.com/PaulR_o_w" rel="noopener noreferrer"&gt;@PaulR_o_w&lt;/a&gt;) as part of my #buildinpublic and #rankinpublic experiment.&lt;/p&gt;

&lt;p&gt;Here's the meta part that makes this interesting: I built &lt;a href="https://boompath.io/" rel="noopener noreferrer"&gt;&lt;strong&gt;BoomPath&lt;/strong&gt;&lt;/a&gt;, an AI-powered SEO platform that goes beyond basic automation. BoomPath:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Analyzes your business&lt;/strong&gt; to understand what you actually do&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Finds strategic keywords&lt;/strong&gt; (not just volume—intent and competition)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitors your competitors&lt;/strong&gt; (what's working for them)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Writes SEO-optimized content&lt;/strong&gt; tailored to your niche&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Builds backlinks automatically&lt;/strong&gt; through directory submissions and strategic outreach&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's not just another SurfSEO or AiSEO clone—it's the entire SEO workflow, automated.&lt;/p&gt;

&lt;p&gt;And now I'm using BoomPath to rank TattooRed. So the stack is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BoomPath (my SEO platform)
    ↓
TattooRed (AI tattoo generator)
    ↓
User-generated content
    ↓
GPT-4o enrichment
    ↓
Automatic SEO pages
    ↓
Rankings (tracked publicly on Twitter)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's turtles all the way down. 🐢&lt;/p&gt;

&lt;p&gt;The beautiful irony? I'm proving BoomPath works by using it on TattooRed, and documenting both journeys publicly. If you want to follow the day-to-day wins, fails, and metrics, I'm posting regular updates on X.&lt;/p&gt;




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

&lt;p&gt;&lt;strong&gt;Core infrastructure:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Next.js 15 (App Router + Server Components)&lt;/li&gt;
&lt;li&gt;Supabase (PostgreSQL + Auth + Storage)&lt;/li&gt;
&lt;li&gt;Vercel (hosting + ISR)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;AI services:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GPT-4o-mini Vision (content generation)&lt;/li&gt;
&lt;li&gt;ModelsLab Flux (tattoo image generation)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;SEO:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;BoomPath (keyword research, competitor analysis, content strategy, backlink building)&lt;/li&gt;
&lt;li&gt;Automated sitemap generation&lt;/li&gt;
&lt;li&gt;Internal linking automation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Development tools:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Claude Code (coding assistant)&lt;/li&gt;
&lt;li&gt;TypeScript&lt;/li&gt;
&lt;li&gt;Tailwind CSS&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🎓 Key Takeaways for Builders
&lt;/h2&gt;

&lt;p&gt;If you're considering programmatic SEO with AI:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;User-generated content is gold&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Let users create the initial input&lt;/li&gt;
&lt;li&gt;AI enriches it into SEO-ready pages&lt;/li&gt;
&lt;li&gt;Everyone wins: users get free value, you get content&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;GPT-4o-mini Vision is underrated&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;90% of GPT-4o quality at 10% the cost&lt;/li&gt;
&lt;li&gt;Perfect for high-volume content generation&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Build recovery systems from day one&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Background jobs WILL fail&lt;/li&gt;
&lt;li&gt;Silent failures are the worst&lt;/li&gt;
&lt;li&gt;Manual recovery buttons save your sanity&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Many-to-many category relations scale&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One piece of content → multiple entry points&lt;/li&gt;
&lt;li&gt;Automatic internal linking&lt;/li&gt;
&lt;li&gt;SEO multiplier effect&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Economics matter more than tech&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;$0.006 per page = infinite runway&lt;/li&gt;
&lt;li&gt;Focus on user acquisition, not content costs&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Use your own products&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Building BoomPath forced me to understand SEO deeply&lt;/li&gt;
&lt;li&gt;Using it on TattooRed proves it works&lt;/li&gt;
&lt;li&gt;Public accountability creates urgency&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  📝 Meta: How This Article Was Written
&lt;/h2&gt;

&lt;p&gt;Full transparency: I wrote this article with Claude's help.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;My role:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Architecture decisions and implementation&lt;/li&gt;
&lt;li&gt;Real-world disasters and solutions (orphan tattoos, API failures)&lt;/li&gt;
&lt;li&gt;Metrics and learnings&lt;/li&gt;
&lt;li&gt;Business strategy&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Claude's role:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Article structure and flow&lt;/li&gt;
&lt;li&gt;Technical explanation clarity&lt;/li&gt;
&lt;li&gt;Editing for dev.to audience&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The result:&lt;/strong&gt; This article in 2 hours instead of 8-10 hours. That's AI as a thinking partner.&lt;/p&gt;




&lt;h2&gt;
  
  
  💬 Let's Discuss
&lt;/h2&gt;

&lt;p&gt;I'm curious about your experiences:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Have you built programmatic SEO systems?&lt;/li&gt;
&lt;li&gt;What's your backup plan for AI API failures?&lt;/li&gt;
&lt;li&gt;How do you handle silent background job failures?&lt;/li&gt;
&lt;li&gt;Ever had an "oh shit" moment at 2 AM?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Drop your thoughts in the comments below.&lt;/strong&gt; I'll reply to everyone.&lt;/p&gt;

&lt;h2&gt;
  
  
  Follow my build-in-public journey: &lt;a href="https://x.com/PaulR_o_w" rel="noopener noreferrer"&gt;Twitter @PaulR_o_w&lt;/a&gt; • &lt;a href="https://tattoored.com" rel="noopener noreferrer"&gt;TattooRed.com&lt;/a&gt; 🔥
&lt;/h2&gt;

</description>
      <category>nextjs</category>
      <category>seo</category>
      <category>buildinpublic</category>
      <category>chatgpt</category>
    </item>
  </channel>
</rss>
