<?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: Sakthivel Murugan</title>
    <description>The latest articles on DEV Community by Sakthivel Murugan (@i_sakthi_7).</description>
    <link>https://dev.to/i_sakthi_7</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%2F4004300%2F33e9e400-a8f9-46fd-b306-e8c55acf2303.png</url>
      <title>DEV Community: Sakthivel Murugan</title>
      <link>https://dev.to/i_sakthi_7</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/i_sakthi_7"/>
    <language>en</language>
    <item>
      <title>How I Built a Hyperlocal Coupon Platform with Next.js Firebase for Small-Town India</title>
      <dc:creator>Sakthivel Murugan</dc:creator>
      <pubDate>Fri, 26 Jun 2026 16:38:33 +0000</pubDate>
      <link>https://dev.to/i_sakthi_7/how-i-built-a-hyperlocal-coupon-platform-with-nextjs-14-firebase-for-small-town-india-4pdc</link>
      <guid>https://dev.to/i_sakthi_7/how-i-built-a-hyperlocal-coupon-platform-with-nextjs-14-firebase-for-small-town-india-4pdc</guid>
      <description>&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;Small local shops in Tier-2/3 Indian cities (think Tirunelveli, Tenkasi, Dindigul) have &lt;strong&gt;zero digital presence&lt;/strong&gt;. No website, no app, no way to offer digital coupons. National platforms like Nearbuy and MagicPin don't serve these towns.&lt;/p&gt;

&lt;p&gt;I'm a developer at &lt;a href="https://blumensoft.in" rel="noopener noreferrer"&gt;Blumensoft Technologies&lt;/a&gt;, and we built &lt;strong&gt;&lt;a href="https://gocoupon.in" rel="noopener noreferrer"&gt;goCoupon&lt;/a&gt;&lt;/strong&gt; — a hyperlocal coupon platform where local shops can create digital coupon codes, and shoppers can claim them for free.&lt;/p&gt;

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

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Technology&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Frontend&lt;/td&gt;
&lt;td&gt;*&lt;em&gt;Next.js *&lt;/em&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Database&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Firebase Firestore&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auth&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Firebase Auth&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hosting&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Google Cloud Run, Firebase App Hosting&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mobile App&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Flutter&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Styling&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Tailwind CSS&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Why Next.js 14?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. SEO is Everything for Us
&lt;/h3&gt;

&lt;p&gt;We need Google to index pages like &lt;code&gt;/offers/tirunelveli&lt;/code&gt; and &lt;code&gt;/restaurants-near-me&lt;/code&gt;. Next.js gives us:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Server-Side Rendering (SSR)&lt;/strong&gt; — Google sees fully rendered HTML&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Incremental Static Regeneration (ISR)&lt;/strong&gt; — Pages rebuild every hour without redeploying&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic metadata&lt;/strong&gt; — Each city page gets unique title, description, and structured data
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Every city page gets unique SEO metadata&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="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Metadata&lt;/span&gt;&lt;span class="o"&gt;&amp;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;city&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getSEOCity&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;city&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="s2"&gt;`Best Offers in &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;city&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; Today | Deals &amp;amp; Coupons`&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="s2"&gt;`Find &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;city&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; offers...`&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;
  
  
  2. App Router + React Server Components
&lt;/h3&gt;

&lt;p&gt;Server Components let us fetch Firestore data without sending the Firebase SDK to the browser. Less JavaScript = faster pages = better Core Web Vitals.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Built-in Sitemap &amp;amp; Robots
&lt;/h3&gt;

&lt;p&gt;Next.js generates &lt;code&gt;sitemap.xml&lt;/code&gt; and &lt;code&gt;robots.txt&lt;/code&gt; dynamically:&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;// sitemap.ts — auto-generates XML sitemap&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;sitemap&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;cities&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;getActiveTerritories&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;cities&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;city&lt;/span&gt; &lt;span class="o"&gt;=&amp;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="s2"&gt;`https://gocoupon.in/offers/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;city&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;lastModified&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;changeFrequency&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;daily&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The SEO Strategy That Worked
&lt;/h2&gt;

&lt;p&gt;We created &lt;strong&gt;16 SEO landing pages&lt;/strong&gt; targeting real search queries:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Page&lt;/th&gt;
&lt;th&gt;Target Keyword&lt;/th&gt;
&lt;th&gt;Monthly Searches&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/today-offers&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;today offers near me&lt;/td&gt;
&lt;td&gt;25,000+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/free-coupons&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;free coupon code&lt;/td&gt;
&lt;td&gt;30,000+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/restaurants-near-me&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;restaurant offers near me&lt;/td&gt;
&lt;td&gt;15,000+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/salons-near-me&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;salon offers near me&lt;/td&gt;
&lt;td&gt;8,000+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/best-deals&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;best deals today&lt;/td&gt;
&lt;td&gt;10,000+&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Each page has:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ JSON-LD structured data (BreadcrumbList, FAQPage)&lt;/li&gt;
&lt;li&gt;✅ Unique H1 with target keyword&lt;/li&gt;
&lt;li&gt;✅ FAQ section (targets Google featured snippets)&lt;/li&gt;
&lt;li&gt;✅ Internal linking to city pages&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Firebase Architecture
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Firestore Structure:
├── businesses/
│   ├── {businessId}
│   │   ├── name, category, city
│   │   └── offers/ (subcollection)
│   │       └── {offerId}
│   │           ├── title, discount, validFrom, validThrough
│   │           └── couponCodes/ (subcollection)
│   │               └── {codeId} — unique per user
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key design decision:&lt;/strong&gt; Every coupon code is unique and non-shareable. When a user claims a coupon, we generate a unique code tied to their user ID. This prevents abuse and gives businesses real tracking.&lt;/p&gt;

&lt;h2&gt;
  
  
  The IST Timezone Trap 🕐
&lt;/h2&gt;

&lt;p&gt;Our Cloud Run server runs on &lt;strong&gt;UTC&lt;/strong&gt;. But our users are in &lt;strong&gt;IST (UTC+5:30)&lt;/strong&gt;. An offer expiring "today" (June 26 IST) was showing as expired at 6:30 PM IST because the server compared against UTC midnight.&lt;/p&gt;

&lt;p&gt;Fix:&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;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;isExpiredIST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;validThrough&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;boolean&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;nowIST&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;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;5.5&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&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;endIST&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;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;validThrough&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;T23:59:59+05:30&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;nowIST&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;endIST&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;h2&gt;
  
  
  Results So Far
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;🏙️ Live across &lt;strong&gt;38 districts&lt;/strong&gt; in Tamil Nadu&lt;/li&gt;
&lt;li&gt;📄 &lt;strong&gt;20+ indexed pages&lt;/strong&gt; on Google (from ~5 before)&lt;/li&gt;
&lt;li&gt;🎟️ Unique coupon codes — no sharing, no abuse&lt;/li&gt;
&lt;li&gt;📱 Flutter mobile app for Android &amp;amp; iOS&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://gocoupon.in" rel="noopener noreferrer"&gt;gocoupon.in&lt;/a&gt;&lt;/strong&gt; — Browse offers near you&lt;/p&gt;

&lt;p&gt;If you're building for local/hyperlocal markets, I'd love to hear your approach. Drop a comment!&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I'm Sakthivel, developer at Blumensoft Technologies, Tirunelveli. We build digital products for small-town India.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>firebase</category>
      <category>webdev</category>
      <category>startup</category>
    </item>
  </channel>
</rss>
