<?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: Seunghyun Kim</title>
    <description>The latest articles on Forem by Seunghyun Kim (@seunghyunkim).</description>
    <link>https://forem.com/seunghyunkim</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%2F3633297%2F16e70047-bf86-4ad0-a73e-340398aff6ae.jpg</url>
      <title>Forem: Seunghyun Kim</title>
      <link>https://forem.com/seunghyunkim</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/seunghyunkim"/>
    <language>en</language>
    <item>
      <title>"Why vibe coding from day one usually backfires (and what actually worked for me)"</title>
      <dc:creator>Seunghyun Kim</dc:creator>
      <pubDate>Thu, 27 Nov 2025 18:03:49 +0000</pubDate>
      <link>https://forem.com/seunghyunkim/why-vibe-coding-from-day-one-usually-backfires-and-what-actually-worked-for-me-56hk</link>
      <guid>https://forem.com/seunghyunkim/why-vibe-coding-from-day-one-usually-backfires-and-what-actually-worked-for-me-56hk</guid>
      <description>&lt;p&gt;I love vibe coding. There is something powerful about opening an editor, following intuition, and letting momentum carry you forward.&lt;/p&gt;

&lt;p&gt;But after shipping multiple products, I learned this the hard way.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Starting with pure vibe coding from day one is one of the fastest ways to create long term chaos.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here is why it usually fails in practice.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Vibe coding optimizes for speed, not structure&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When you start with vibes only, everything feels fast at first.&lt;/p&gt;

&lt;p&gt;You skip architecture.&lt;br&gt;&lt;br&gt;
You skip naming.&lt;br&gt;&lt;br&gt;
You skip state design.&lt;br&gt;&lt;br&gt;
You skip data modeling.&lt;/p&gt;

&lt;p&gt;It feels productive. Until you need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add billing&lt;/li&gt;
&lt;li&gt;Add permissions&lt;/li&gt;
&lt;li&gt;Add emails&lt;/li&gt;
&lt;li&gt;Add analytics&lt;/li&gt;
&lt;li&gt;Or just debug one complex bug&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At that point, every change becomes a minefield.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Refactors become emotional, not technical&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;With a weak foundation, refactoring stops being a technical decision and turns into emotional resistance:&lt;/p&gt;

&lt;p&gt;“I will just hack it for now.”&lt;br&gt;&lt;br&gt;
“I will clean this later.”&lt;br&gt;&lt;br&gt;
“I cannot touch this file anymore.”&lt;/p&gt;

&lt;p&gt;That is when projects quietly die. Not from lack of ideas, but from invisible technical debt.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. What finally worked for me&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;What changed everything was flipping the order:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First, lock a &lt;strong&gt;boring but rock solid foundation&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Then, vibe on top of it freely&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once auth, billing, emails, SEO, analytics, and deployment were stable, I could vibe code with zero fear. I could experiment without breaking the company.&lt;/p&gt;

&lt;p&gt;Speed became sustainable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Vibe coding works best inside guardrails&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The best workflow I found looks like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rigid foundation&lt;/li&gt;
&lt;li&gt;Flexible feature layer&lt;/li&gt;
&lt;li&gt;Fast iteration on business logic&lt;/li&gt;
&lt;li&gt;Safe deletion and rewrites&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Inside those guardrails, vibe coding becomes a superpower instead of a liability.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. How I personally avoid rebuilding the same base now&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After rebuilding the same SaaS base too many times, I turned my internal setup into a reusable starter so I would never have to fight this battle again. That eventually became &lt;strong&gt;Sabo&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I now start every product with a stable base and then vibe code 100 percent of the product logic on top of it. The difference in stress and shipping speed is dramatic.&lt;/p&gt;

&lt;p&gt;If you are curious, this is the setup I now start from:&lt;br&gt;&lt;br&gt;
&lt;a href="https://getsabo.com/?utm_source=devto" rel="noopener noreferrer"&gt;getsabo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. The real takeaway&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Vibe coding is not the enemy.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Starting without a foundation is.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If your base is solid, vibe coding becomes fun, fast, and safe.&lt;br&gt;&lt;br&gt;
If your base is shaky, vibe coding just accelerates your future pain.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Question for the forum&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Have you ever had a project die because the foundation could not keep up with the speed of your ideas?&lt;/p&gt;

&lt;p&gt;Or do you still prefer starting fully from vibes and refactoring later?&lt;/p&gt;

&lt;p&gt;I am genuinely curious how others here balance freedom vs structure.&lt;/p&gt;

</description>
      <category>vibecoding</category>
      <category>saas</category>
      <category>startup</category>
      <category>nextjs</category>
    </item>
    <item>
      <title>Building a production ready SaaS starter with Next.js 16: what actually took the longest</title>
      <dc:creator>Seunghyun Kim</dc:creator>
      <pubDate>Thu, 27 Nov 2025 17:55:05 +0000</pubDate>
      <link>https://forem.com/seunghyunkim/building-a-production-ready-saas-starter-with-nextjs-16-what-actually-took-the-longest-kmn</link>
      <guid>https://forem.com/seunghyunkim/building-a-production-ready-saas-starter-with-nextjs-16-what-actually-took-the-longest-kmn</guid>
      <description>&lt;p&gt;When people talk about building a SaaS, the focus is often on the core idea. In reality, most of the time disappears into the same invisible foundation work that never shows up in demos.&lt;/p&gt;

&lt;p&gt;Landing pages.&lt;br&gt;
Authentication.&lt;br&gt;
Billing.&lt;br&gt;
Emails.&lt;br&gt;
SEO.&lt;br&gt;
Analytics.&lt;br&gt;
Monitoring.&lt;br&gt;
Testing.&lt;/p&gt;

&lt;p&gt;Before any real feature exists, weeks are already gone.&lt;/p&gt;

&lt;p&gt;We recently built a production ready SaaS starter on top of Next.js 16, and I want to share what actually took the longest time, what broke in production, and what we would do differently if we started again today.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Authentication was not the hard part. The edge cases were&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Setting up basic email and OAuth login was easy. The real pain started with everything around it.&lt;/p&gt;

&lt;p&gt;Session refresh across server components&lt;/p&gt;

&lt;p&gt;Token sync between API routes and middleware&lt;/p&gt;

&lt;p&gt;Handling partial OAuth profiles&lt;/p&gt;

&lt;p&gt;Account linking edge cases&lt;/p&gt;

&lt;p&gt;Deleting users and cascading data safely&lt;/p&gt;

&lt;p&gt;The basic tutorial version works in one afternoon. Making it safe in production is what took days.&lt;/p&gt;

&lt;p&gt;If you are building your own auth, design the account lifecycle first. Registration is only a small part of it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Subscriptions are easy until invoices and webhooks enter the room&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The first Stripe checkout took less than an hour. What followed took a week.&lt;/p&gt;

&lt;p&gt;Webhook reliability&lt;/p&gt;

&lt;p&gt;Retrying failed payments&lt;/p&gt;

&lt;p&gt;Grace periods&lt;/p&gt;

&lt;p&gt;Plan downgrades without breaking access&lt;/p&gt;

&lt;p&gt;Invoice state matching your internal DB state&lt;/p&gt;

&lt;p&gt;The hardest part was not charging users. It was keeping subscription state consistent between Stripe, the database, and the frontend UI.&lt;/p&gt;

&lt;p&gt;Strong advice: model your subscription states on paper before writing a single line of billing code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Emails were a silent source of production bugs&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Email feels trivial until it breaks user trust.&lt;/p&gt;

&lt;p&gt;Verification emails going to spam&lt;/p&gt;

&lt;p&gt;Password reset links expiring incorrectly&lt;/p&gt;

&lt;p&gt;Edge cases when users change emails mid session&lt;/p&gt;

&lt;p&gt;Race conditions between auth and email dispatch&lt;/p&gt;

&lt;p&gt;We ended up treating email as a first class production system, not a utility. Logging, retries, and delivery monitoring became mandatory.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. SEO and metadata took longer than expected&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Next.js makes rendering easy. SEO correctness still takes discipline.&lt;/p&gt;

&lt;p&gt;Canonical URLs&lt;/p&gt;

&lt;p&gt;OG and Twitter cards&lt;/p&gt;

&lt;p&gt;Sitemap updates during dynamic routing&lt;/p&gt;

&lt;p&gt;Indexing control between preview and production&lt;/p&gt;

&lt;p&gt;Structured data validation&lt;/p&gt;

&lt;p&gt;None of it is conceptually hard, but missing even one piece quietly hurts distribution for months.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Analytics without polluting the app took multiple rewrites&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We wanted clean analytics without slowing the app.&lt;/p&gt;

&lt;p&gt;Client side tracking without hydration errors&lt;/p&gt;

&lt;p&gt;Server side events for billing&lt;/p&gt;

&lt;p&gt;Privacy safe defaults&lt;/p&gt;

&lt;p&gt;Mapping anonymous to authenticated users cleanly&lt;/p&gt;

&lt;p&gt;The mistake we made early was adding analytics after everything else. It should be part of the core architecture from the beginning.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Testing was delayed. That was a mistake&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;E2E tests always come last. That is where the real bugs hide.&lt;/p&gt;

&lt;p&gt;The moment we added full Playwright coverage for:&lt;/p&gt;

&lt;p&gt;Auth flows&lt;/p&gt;

&lt;p&gt;Checkout&lt;/p&gt;

&lt;p&gt;Webhooks&lt;/p&gt;

&lt;p&gt;Dashboard state&lt;/p&gt;

&lt;p&gt;We immediately discovered issues that had been invisible for weeks.&lt;/p&gt;

&lt;p&gt;Testing earlier would have saved real production incidents.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What we learned overall&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Infrastructure always takes longer than expected.&lt;/p&gt;

&lt;p&gt;Most SaaS bugs live in the invisible glue code.&lt;/p&gt;

&lt;p&gt;Shipping fast is only possible if foundations are boringly solid.&lt;/p&gt;

&lt;p&gt;Starters are not about speed. They are about eliminating entire failure classes.&lt;/p&gt;

&lt;p&gt;This experience eventually led us to turn our internal setup into a reusable SaaS starter called Sabo, simply because we never wanted to repeat this whole process again.&lt;br&gt;
You can find it here if you are curious: &lt;a href="https://getsabo.com/?utm_source=devto" rel="noopener noreferrer"&gt;getsabo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But even if you never use any starter kit, the lessons above apply to every serious SaaS build.&lt;/p&gt;

&lt;p&gt;If you are building a SaaS right now&lt;/p&gt;

&lt;p&gt;Ask yourself:&lt;/p&gt;

&lt;p&gt;Do you fully understand your auth edge cases?&lt;/p&gt;

&lt;p&gt;Can your billing system survive failed payments safely?&lt;/p&gt;

&lt;p&gt;Are emails observable and debuggable?&lt;/p&gt;

&lt;p&gt;Will Google index exactly what you expect?&lt;/p&gt;

&lt;p&gt;Do you trust your E2E tests more than your staging environment?&lt;/p&gt;

&lt;p&gt;If even one answer is “not really”, that is where most long term pain starts.&lt;/p&gt;

&lt;p&gt;If this was useful, I am happy to share deeper writeups on any of these parts in follow up posts. Auth, billing, email delivery, and SEO each deserve their own war stories.&lt;/p&gt;

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