<?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: lanba</title>
    <description>The latest articles on DEV Community by lanba (@lanba_a7241f798242396b44f).</description>
    <link>https://dev.to/lanba_a7241f798242396b44f</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%2F4115244%2Fb6d63d35-9f1a-4925-905d-711d8fd5b880.jpeg</url>
      <title>DEV Community: lanba</title>
      <link>https://dev.to/lanba_a7241f798242396b44f</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/lanba_a7241f798242396b44f"/>
    <language>en</language>
    <item>
      <title>I Built an AI That Turns Any Topic Into a Structured YouTube Course — 3 Real Lessons From Shipping It Solo</title>
      <dc:creator>lanba</dc:creator>
      <pubDate>Tue, 08 Sep 2026 08:17:21 +0000</pubDate>
      <link>https://dev.to/lanba_a7241f798242396b44f/i-built-an-ai-that-turns-any-topic-into-a-structured-youtube-course-3-real-lessons-from-shipping-3jko</link>
      <guid>https://dev.to/lanba_a7241f798242396b44f/i-built-an-ai-that-turns-any-topic-into-a-structured-youtube-course-3-real-lessons-from-shipping-3jko</guid>
      <description>&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;Every time I wanted to learn something new on YouTube — Excel, guitar, a new language — I hit the same wall: hundreds of videos on the topic, a lot of them near-duplicates, no real order, and no idea how long it would actually take to go from zero to competent.&lt;/p&gt;

&lt;p&gt;So I built &lt;a href="https://cursosenvideo.online" rel="noopener noreferrer"&gt;Cursos en Video&lt;/a&gt;: you type a topic, and it builds you a structured learning path entirely from existing YouTube videos — searched, filtered, ordered by prerequisite, deduplicated, with a time estimate for the whole thing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The stack
&lt;/h2&gt;

&lt;p&gt;Nothing exotic on purpose: Next.js 16 (App Router) + TypeScript + Tailwind, Supabase (Postgres + Auth + RLS), OpenAI Structured Outputs (&lt;code&gt;strict: true&lt;/code&gt;) to generate the curriculum, and the YouTube Data API v3 (direct REST, no SDK) to search and pull video metadata.&lt;/p&gt;

&lt;p&gt;The core flow: &lt;code&gt;/api/generate-path&lt;/code&gt; calls the YouTube Data API to gather candidate videos for a topic, filters them, and hands them to OpenAI to order into modules by prerequisite. YouTube's default quota is 10,000 units/day, and a single &lt;code&gt;search.list&lt;/code&gt; call costs 100 — so every request is rate-limited (3/minute, 15/day per user), enforced with an atomic Postgres function rather than in application memory, and it fails open (with a Sentry alert) if the limiter itself breaks — better to occasionally let one extra request through than to take the whole app down over a rate-limiter bug.&lt;/p&gt;

&lt;p&gt;Here are three things I ran into that I think are worth sharing.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Never let an LLM invent an identifier
&lt;/h2&gt;

&lt;p&gt;The app also recommends affiliate resources (mostly books) related to a topic. Early on I asked OpenAI to suggest books &lt;em&gt;and&lt;/em&gt; generate the Amazon product link. Bad idea: LLMs will happily hallucinate an ASIN that points to the wrong product, or to nothing at all.&lt;/p&gt;

&lt;p&gt;The fix was to change what I was asking the model to do. Now OpenAI only returns real, well-known books (title + author + why it fits) — and is never asked for an ASIN or a URL. A separate, fully deterministic function builds an Amazon &lt;strong&gt;search-results&lt;/strong&gt; link for "title + author" with my affiliate tag. It still earns commission without depending on the model getting the exact product right.&lt;/p&gt;

&lt;p&gt;General lesson: if a piece of data has to be correct, don't let the model generate it — let it generate the inputs to a deterministic lookup instead.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Concurrency bugs show up exactly where you don't expect them
&lt;/h2&gt;

&lt;p&gt;There's a daily cron that emails newsletter subscribers about newly-approved affiliate resources for topics they follow. I later added a second trigger: notify subscribers the moment an admin approves a resource, instead of waiting for the next day's cron.&lt;/p&gt;

&lt;p&gt;Two triggers reading and writing the same table sounds harmless — until two approvals land seconds apart. Both would read the same "not yet notified" resources before either marked them as sent, and both would happily email the same subscribers twice.&lt;/p&gt;

&lt;p&gt;The fix: claim each resource atomically by setting a &lt;code&gt;notified_at&lt;/code&gt; timestamp in a single &lt;code&gt;UPDATE ... WHERE notified_at IS NULL&lt;/code&gt;, &lt;em&gt;before&lt;/em&gt; sending anything, relying on Postgres's row locking. A second overlapping run's &lt;code&gt;WHERE&lt;/code&gt; clause stops matching the instant the first run's update commits — no explicit lock needed. If sending fails outright, the claim is released (&lt;code&gt;notified_at = null&lt;/code&gt;) so the next run retries it, instead of silently losing it.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Sometimes the boring option is the correct one
&lt;/h2&gt;

&lt;p&gt;I needed a way to export a learning path to PDF. The obvious modern answer is a headless-browser PDF service — Puppeteer, or a hosted API. On a serverless deploy that means cold starts, timeout risk, and a new dependency to keep alive.&lt;/p&gt;

&lt;p&gt;Instead: a plain read-only page that reuses the same curriculum rendering already built for the public share links, with print-specific CSS, and the browser's own "Print → Save as PDF." Zero new dependencies, zero server-side rendering cost, zero timeout risk — and it looks exactly like what the user already sees on screen.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;p&gt;Multi-language support is next on the list, along with a few more affiliate networks. If you're curious, &lt;a href="https://cursosenvideo.online" rel="noopener noreferrer"&gt;Cursos en Video&lt;/a&gt; is free, no signup needed to try it — currently Spanish-only, but I'd genuinely like to know if there's interest in an English version. Building this solo, so feedback (harsh included) is very welcome.&lt;/p&gt;

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