<?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: 윤병준</title>
    <description>The latest articles on DEV Community by 윤병준 (@workat5am).</description>
    <link>https://dev.to/workat5am</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%2F3862182%2Fdc29ea02-eac4-46ac-8ffa-f33ec00cb773.png</url>
      <title>DEV Community: 윤병준</title>
      <link>https://dev.to/workat5am</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/workat5am"/>
    <language>en</language>
    <item>
      <title>I Built 68 Free Online Tools in 2 Weeks with Next.js — Here's the Architecture</title>
      <dc:creator>윤병준</dc:creator>
      <pubDate>Sun, 05 Apr 2026 12:08:54 +0000</pubDate>
      <link>https://dev.to/workat5am/i-built-68-free-online-tools-in-2-weeks-with-nextjs-heres-the-architecture-h5e</link>
      <guid>https://dev.to/workat5am/i-built-68-free-online-tools-in-2-weeks-with-nextjs-heres-the-architecture-h5e</guid>
      <description>&lt;p&gt;&lt;em&gt;A frontend developer with a 4-hour daily commute, two young kids, and zero free time decided to build passive income anyway.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Why a guy with no free time started a side project&lt;/li&gt;
&lt;li&gt;The Stack&lt;/li&gt;
&lt;li&gt;The Tool Factory Pattern&lt;/li&gt;
&lt;li&gt;i18n Without next-intl&lt;/li&gt;
&lt;li&gt;SEO That Scales&lt;/li&gt;
&lt;li&gt;Monetization (the honest version)&lt;/li&gt;
&lt;li&gt;What I Got Wrong&lt;/li&gt;
&lt;li&gt;Current Stats (week 2)&lt;/li&gt;
&lt;li&gt;What's Next&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Why a Guy with No Free Time Started a Side Project {#why}
&lt;/h2&gt;

&lt;p&gt;My daily schedule looks like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;5:00 AM&lt;/strong&gt; — Wake up&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;5:00–7:00&lt;/strong&gt; — Commute (2 hours one way)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;7:00–4:00 PM&lt;/strong&gt; — Work&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;4:00–6:00&lt;/strong&gt; — Commute back&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;6:00–9:00&lt;/strong&gt; — Dinner, bath time, bedtime for two daughters (ages 6 and 7)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;9:00–11:00&lt;/strong&gt; — The only window I have&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I've been a frontend developer for 10 years. I'm not exceptional. I'll never build the next React or invent a new state management library. But I'm fast at copying patterns that work. That's my only real skill.&lt;/p&gt;

&lt;p&gt;One day on the train I was searching "퇴직금 계산기" (Korean severance pay calculator) and landed on a terrible website. Slow, full of pop-ups, wrong calculations. I thought: &lt;em&gt;I could build this in a day. And if I build 50 of these...&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Two weeks later, &lt;a href="https://rhand.app" rel="noopener noreferrer"&gt;rhand.app&lt;/a&gt; has 68 free tools in 6 languages.&lt;/p&gt;




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

&lt;p&gt;Nothing fancy. I optimized for speed-to-ship, not elegance.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Next.js 16&lt;/strong&gt; (App Router)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tailwind CSS 4&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vercel&lt;/strong&gt; (free tier)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backend&lt;/strong&gt;: None&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Database&lt;/strong&gt;: None&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Testing&lt;/strong&gt;: Vitest + Playwright&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why no backend? Every tool runs in the browser. A loan calculator doesn't need an API. A password generator doesn't need a database. Client-side means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Zero server costs at any scale&lt;/li&gt;
&lt;li&gt;Zero privacy concerns (no data leaves the browser)&lt;/li&gt;
&lt;li&gt;Zero DevOps&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My total monthly cost is $0.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Tool Factory Pattern
&lt;/h2&gt;

&lt;p&gt;This is the only clever thing I did. Instead of building 68 unique apps, I built a factory.&lt;/p&gt;

&lt;p&gt;Every tool follows the same structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/lib/tools/{slug}/
  └── calculator.ts          # Pure functions. No React.

src/app/[locale]/tools/{slug}/
  ├── page.tsx                # Server component (SEO, metadata)
  └── {Name}Client.tsx        # Client component (interactive UI)

src/lib/dictionaries/tools/{locale}/
  └── {slug}.json             # All text: UI labels, FAQ, meta tags
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The logic layer is boring on purpose
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/lib/tools/compound-interest-calculator/calculator.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;calculateCompoundInterest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CompoundInput&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;CompoundResult&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;principal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;monthlyContribution&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;annualRate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;years&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;frequency&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;input&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;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;annualRate&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;100&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;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;frequency&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;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;years&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;amount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;principal&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;monthlyContribution&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pure functions. No React imports. No side effects. Testable in milliseconds.&lt;/p&gt;

&lt;h3&gt;
  
  
  The page layer is copy-paste
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Every page.tsx looks almost identical&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;ToolPage&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;locale&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;params&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;dict&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;getToolDictionary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;locale&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="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;SEOHead&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ToolLayout&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ToolClient&lt;/span&gt; &lt;span class="nx"&gt;dict&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ToolLayout&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;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;By tool #10 I stopped thinking about architecture. By tool #40 it was muscle memory. Adding a new tool takes about &lt;strong&gt;4-6 hours&lt;/strong&gt; including translations and tests.&lt;/p&gt;

&lt;p&gt;The boring repetition is the point. I don't need creativity. I need volume.&lt;/p&gt;




&lt;h2&gt;
  
  
  i18n Without next-intl
&lt;/h2&gt;

&lt;p&gt;I support 6 languages: English, Korean, Japanese, Chinese, Spanish, German.&lt;/p&gt;

&lt;p&gt;I didn't use next-intl. Instead, each tool has its own dictionary:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;src/lib/dictionaries/tools/en/tip-calculator.json&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"meta"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Tip Calculator — Split Bills &amp;amp; Calculate Gratuity"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Calculate tips for restaurants, taxis, and services..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"keywords"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tip calculator, gratuity calculator, bill splitter..."&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"heading"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Tip Calculator"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"inputs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"billAmount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Bill Amount"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"tipPercent"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Tip Percentage"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"splitCount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Split Between"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"faq"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"q"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"How much should I tip?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"a"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;68 tools × 6 languages = 408 JSON files. Sounds insane. But:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each file is self-contained (no cross-references)&lt;/li&gt;
&lt;li&gt;Adding a language = copying a folder and translating&lt;/li&gt;
&lt;li&gt;SEO keywords are per-tool, per-language (critical for ranking)&lt;/li&gt;
&lt;li&gt;No runtime overhead — loaded server-side, passed as props&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  SEO That Scales
&lt;/h2&gt;

&lt;p&gt;Most tool sites ignore SEO. I made it a first-class concern.&lt;/p&gt;

&lt;h3&gt;
  
  
  Schema.org on every page
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Automatically generated for each tool&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;WebApplication&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Tip Calculator&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;applicationCategory&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;FinanceApplication&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;offers&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;price&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;inLanguage&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ko&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ja&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;zh&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;es&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;de&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  FAQPage schema from dictionary
&lt;/h3&gt;

&lt;p&gt;Every tool has 8-10 FAQ items. These serve double duty:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Users actually read them&lt;/li&gt;
&lt;li&gt;Google uses them for "People also ask" rich results
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Auto-generated from the faq array in each dictionary&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;FAQPage&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mainEntity&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;faq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Question&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;acceptedAnswer&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Answer&lt;/span&gt;&lt;span class="dl"&gt;"&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="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;a&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;h3&gt;
  
  
  Long-tail keywords &amp;gt; short keywords
&lt;/h3&gt;

&lt;p&gt;I don't try to rank for "calculator." I try to rank for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Korean severance pay calculator 2026 tax rate"&lt;/li&gt;
&lt;li&gt;"tip calculator split bill 4 people"&lt;/li&gt;
&lt;li&gt;"compound interest calculator with monthly contribution"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The FAQ naturally covers these long-tail variations. Each FAQ item is essentially a landing keyword.&lt;/p&gt;

&lt;h3&gt;
  
  
  hreflang = 6x visibility
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;alternates&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;languages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;en&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://rhand.app/en/tools/tip-calculator&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;ko&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://rhand.app/ko/tools/tip-calculator&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;ja&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://rhand.app/ja/tools/tip-calculator&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&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;Instead of one page competing for "tip calculator," I have six pages competing in six different language markets. No cannibalization.&lt;/p&gt;

&lt;h3&gt;
  
  
  Internal linking with semantic clusters
&lt;/h3&gt;

&lt;p&gt;I don't just link to "tools in the same category." I built a relationship map:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;TOOL_RELATIONSHIPS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;loan-calculator&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;compound-interest-calculator&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;rent-vs-buy-calculator&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;take-home-pay&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tip-calculator&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;currency-converter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tax-free-calculator&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;percentage-calculator&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="c1"&gt;// 68 tools mapped&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each tool links to 3-4 semantically related tools, not just category neighbors. "Loan calculator" links to "compound interest" and "rent vs buy" — because that's the user's actual journey.&lt;/p&gt;




&lt;h2&gt;
  
  
  Monetization (the honest version)
&lt;/h2&gt;

&lt;p&gt;I'm making $0 right now.&lt;/p&gt;

&lt;p&gt;AdSense is pending review. I built the ad slots into every tool page, but they're empty. The plan:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Primary&lt;/strong&gt;: AdSense display ads (2-3 slots per tool page)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secondary&lt;/strong&gt;: Affiliate links where natural (shoe retailers on shoe size converter, etc.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Target&lt;/strong&gt;: $10K MRR (ambitious, I know)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The math I'm betting on:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;68 tools × ~5,000 monthly visits each = 340,000 pageviews
340,000 × $3 RPM = ~$1,000/month

Scale to 200 tools = ~$3,000/month
Improve RPM with targeted content = $5,000-10,000/month
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is all projection. Reality could be 10x worse or 10x better. I'll share real numbers when I have them.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Got Wrong
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. I built too many tools before validating demand
&lt;/h3&gt;

&lt;p&gt;I should have built 10 tools, gotten traffic, then built 10 more. Instead I built 68 in a sprint. Some of them probably have zero search demand. I won't know which ones until Search Console data matures.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. I underestimated content quality
&lt;/h3&gt;

&lt;p&gt;Tools are easy. Writing good FAQ content in 6 languages is hard. Some of my Japanese and Chinese descriptions are mediocre. I'll need to revisit these.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. I ignored community from the start
&lt;/h3&gt;

&lt;p&gt;Building in isolation means no early feedback. I should have posted on dev.to, Reddit, and Twitter from day one. I'm starting now — two weeks late.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. AdSense approval takes time
&lt;/h3&gt;

&lt;p&gt;I assumed "build it and ads will come." AdSense review is still pending after two weeks. No revenue until that's resolved.&lt;/p&gt;




&lt;h2&gt;
  
  
  Current Stats (Week 2)
&lt;/h2&gt;

&lt;p&gt;Let me be completely honest:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;68 tools&lt;/strong&gt; live&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;6 languages&lt;/strong&gt; (en, ko, ja, zh, es, de)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;237 pages&lt;/strong&gt; indexed by Google&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;263 keywords&lt;/strong&gt; showing impressions in Search Console&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;~25 visitors/week&lt;/strong&gt; (yes, that's tiny)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;$0 revenue&lt;/strong&gt; (AdSense pending)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;$0 costs&lt;/strong&gt; (Vercel free tier)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;2 weeks&lt;/strong&gt; of development&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Top Search Console keywords (all 0 clicks, but showing impressions):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"utm builder" — 38 impressions&lt;/li&gt;
&lt;li&gt;"utm generator" — 31 impressions&lt;/li&gt;
&lt;li&gt;"xml sitemap" — 28 impressions&lt;/li&gt;
&lt;li&gt;"favicon checker" — 19 impressions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's early. Very early. But 237 pages are indexed and 263 keywords are showing up. The SEO foundation is there. Now it's a waiting game.&lt;/p&gt;




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

&lt;h3&gt;
  
  
  This month
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Get AdSense approved&lt;/li&gt;
&lt;li&gt;Post on dev.to, Product Hunt, and relevant communities&lt;/li&gt;
&lt;li&gt;Monitor Search Console — double down on tools that get impressions&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Next 3 months
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Add 30 more tools based on actual search demand (not guessing)&lt;/li&gt;
&lt;li&gt;Improve content quality for JA/ZH translations&lt;/li&gt;
&lt;li&gt;Build backlinks through content marketing&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  6 months
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Target: 100+ tools, 50K monthly visits, first $1K month&lt;/li&gt;
&lt;li&gt;Start sharing revenue numbers publicly&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Part Nobody Tells You
&lt;/h2&gt;

&lt;p&gt;I've been a developer for 10 years. I've seen dozens of "I quit my job and built a SaaS" success stories. They make it look like the hard part is building. It's not.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Building is the easy part.&lt;/strong&gt; I proved that — 68 tools in 2 weeks. The architecture works. The code is clean. The SEO is set up properly. The translations are done.&lt;/p&gt;

&lt;p&gt;And yet I have 25 visitors a week.&lt;/p&gt;

&lt;p&gt;Nobody is coming.&lt;/p&gt;

&lt;p&gt;I think a lot of developers fall into this trap. We're comfortable building. We can always add one more feature, fix one more bug, refactor one more component. It feels productive. But it's actually procrastination disguised as work.&lt;/p&gt;

&lt;p&gt;The real challenge — the one I'm facing right now — is everything that happens &lt;em&gt;after&lt;/em&gt; you ship:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Writing about your project (like this post)&lt;/li&gt;
&lt;li&gt;Sharing it in communities without feeling like a spammer&lt;/li&gt;
&lt;li&gt;Waiting months for SEO to kick in&lt;/li&gt;
&lt;li&gt;Accepting that most of your 68 tools might never get traffic&lt;/li&gt;
&lt;li&gt;Doing marketing when your entire career has been engineering&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I have a 4-hour daily commute and two young daughters. I get about 2 hours a night to work on this. Some nights I fall asleep before I even open my laptop. The dream of "passive income" and "indie developer freedom" sounds romantic until you're on month 1 with $0 revenue and 25 weekly visitors.&lt;/p&gt;

&lt;p&gt;But here's why I'm not stopping:&lt;/p&gt;

&lt;p&gt;My commute costs me 4 hours every day. That's 1,000 hours a year of my life spent on trains. If this project — or the next one, or the one after that — eventually generates even $2,000/month, I can work remotely. I get those 1,000 hours back. I get to see my kids in the morning.&lt;/p&gt;

&lt;p&gt;That's not a business plan. That's a reason to keep going.&lt;/p&gt;




&lt;h2&gt;
  
  
  Try It
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://rhand.app" rel="noopener noreferrer"&gt;rhand.app&lt;/a&gt; — 68 free tools, 6 languages, no signup.&lt;/p&gt;

&lt;p&gt;I'm not going to pretend this is a polished product. I built 68 tools in 2 weeks. There are bugs. Some translations are awkward. Some calculators might have edge cases I haven't found.&lt;/p&gt;

&lt;p&gt;But every tool works. Every tool is free. Every tool runs in your browser without sending your data anywhere.&lt;/p&gt;

&lt;p&gt;If you've tried to build passive income as a developer and struggled — I'd genuinely love to hear your story. Not the success story. The honest one. What did you try? Where did you get stuck? Are you still going?&lt;/p&gt;

&lt;p&gt;Drop a comment below — I read every one.&lt;/p&gt;

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