<?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: Naeem Ullah</title>
    <description>The latest articles on DEV Community by Naeem Ullah (@enaeemullah).</description>
    <link>https://dev.to/enaeemullah</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%2F882985%2F8d916597-1f06-4027-99e8-30c7a3b79e14.jpg</url>
      <title>DEV Community: Naeem Ullah</title>
      <link>https://dev.to/enaeemullah</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/enaeemullah"/>
    <language>en</language>
    <item>
      <title>I Built a 44-Page Calculator Site With Next.js ISR — Here's the Architecture That Actually Ranks</title>
      <dc:creator>Naeem Ullah</dc:creator>
      <pubDate>Sat, 18 Jul 2026 14:37:27 +0000</pubDate>
      <link>https://dev.to/enaeemullah/i-built-a-44-page-calculator-site-with-nextjs-isr-heres-the-architecture-that-actually-ranks-1g7o</link>
      <guid>https://dev.to/enaeemullah/i-built-a-44-page-calculator-site-with-nextjs-isr-heres-the-architecture-that-actually-ranks-1g7o</guid>
      <description>&lt;p&gt;Most calculator sites are a graveyard of orphan pages: 50 tools, no structure, everything competing against everything. I rebuilt mine — seecalc.com — around a hub-and-spoke architecture on Next.js with ISR, and it changed how Google treats the entire domain. Here's the full setup.&lt;/p&gt;

&lt;p&gt;The problem with flat calculator sites&lt;/p&gt;

&lt;p&gt;My first version was flat: /date-calculator, /cd-rate-calculator, /cap-rate-calculator — all siblings, all fighting for crawl budget and authority independently.&lt;/p&gt;

&lt;p&gt;Two symptoms showed up in Search Console:&lt;/p&gt;

&lt;p&gt;Click concentration. The homepage absorbed most clicks while individual tools sat at positions 10–20 — close enough to taste page one, never getting there.&lt;br&gt;
No topical clustering. Google had no signal that my date tools formed a coherent topic. Each page ranked (or didn't) on its own.&lt;/p&gt;

&lt;p&gt;If your internal linking graph is flat, your authority distribution is flat. Spoke pages stuck at position 12 usually don't have a content problem — they have a link-equity problem.&lt;/p&gt;

&lt;p&gt;Hub-and-spoke: the structure&lt;/p&gt;

&lt;p&gt;The fix is boring and effective:&lt;/p&gt;

&lt;p&gt;/date-calculator            ← HUB (broad head term)&lt;br&gt;
├── /days-between-dates     ← spoke&lt;br&gt;
├── /date-plus-days         ← spoke&lt;br&gt;
├── /weeks-between-dates    ← spoke&lt;br&gt;
├── /business-days-calculator&lt;br&gt;
└── /age-calculator&lt;/p&gt;

&lt;p&gt;Rules I enforce in code, not by hand:&lt;/p&gt;

&lt;p&gt;Every spoke links up to its hub in the intro paragraph and breadcrumb.&lt;br&gt;
The hub links down to every spoke with descriptive anchor text (not "click here").&lt;br&gt;
Spokes cross-link laterally only when contextually justified (days-between → business-days makes sense; days-between → cap-rate does not).&lt;br&gt;
No orphans. A page that isn't reachable within 2 clicks from a hub doesn't ship.&lt;/p&gt;

&lt;p&gt;I keep the topology in a single config file so links are generated, not remembered:&lt;/p&gt;

&lt;p&gt;ts// clusters.ts&lt;br&gt;
export const clusters = {&lt;br&gt;
  "date-calculator": {&lt;br&gt;
    hub: { slug: "date-calculator", title: "Date Calculator" },&lt;br&gt;
    spokes: [&lt;br&gt;
      { slug: "days-between-dates", title: "Days Between Dates" },&lt;br&gt;
      { slug: "date-plus-days", title: "Add Days to a Date" },&lt;br&gt;
      { slug: "business-days-calculator", title: "Business Days Calculator" },&lt;br&gt;
      // ...&lt;br&gt;
    ],&lt;br&gt;
  },&lt;br&gt;
  // finance cluster, health cluster...&lt;br&gt;
} as const;&lt;/p&gt;

&lt;p&gt;Every page component pulls its cluster and renders  from this map. Add a spoke to the config → hub updates, siblings update, sitemap updates. Zero manual linking drift.&lt;/p&gt;

&lt;p&gt;Why ISR instead of pure SSG or client-only&lt;/p&gt;

&lt;p&gt;The calculators themselves are client-side (instant, no server round-trip). But the pages are statically generated with Incremental Static Regeneration:&lt;/p&gt;

&lt;p&gt;ts// app/[cluster]/[tool]/page.tsx&lt;br&gt;
export const revalidate = 86400; // rebuild daily&lt;/p&gt;

&lt;p&gt;export async function generateStaticParams() {&lt;br&gt;
  return Object.values(clusters).flatMap(c =&amp;gt;&lt;br&gt;
    [c.hub, ...c.spokes].map(t =&amp;gt; ({ tool: t.slug }))&lt;br&gt;
  );&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;Reasons this combination wins for SEO tool sites:&lt;/p&gt;

&lt;p&gt;Full HTML at crawl time. Googlebot gets rendered content, headings, FAQ markup — not a JS shell. Client-only React tools consistently underperform in my Search Console data.&lt;br&gt;
Content updates without redeploys. I run periodic content-enrichment passes (benchmark tables, sourced data, FAQ expansions). With revalidate, updated content ships on the next request after the window — no CI pipeline run for a copy change.&lt;br&gt;
CWV for free. Static HTML + client hydration only for the calculator widget = green LCP/CLS, which matters more post-INP.&lt;/p&gt;

&lt;p&gt;Content enrichment: what moved spokes, what didn't&lt;/p&gt;

&lt;p&gt;Structure gets you crawled and clustered. It doesn't get you ranked on its own. I ran an enrichment pass across all 44 pages. What measurably helped:&lt;/p&gt;

&lt;p&gt;Sourced benchmark tables. On the CD rate calculator, adding a current-rates comparison table (with cited sources and a last-updated date) beat any amount of prose. Tables win featured snippets; paragraphs don't.&lt;br&gt;
Answering the adjacent question. People on "days between dates" also ask "does it include the end date?" A 2-sentence FAQ with FAQPage schema captured long-tail impressions the tool alone never triggered.&lt;br&gt;
E-E-A-T signals on YMYL-adjacent pages. Financial calculators got methodology notes and formula transparency. Rankings on money pages responded; date pages didn't care.&lt;/p&gt;

&lt;p&gt;What didn't help: adding word count for its own sake. A 400-word page that answers the query outranks a 1,500-word page that pads it. I cut copy on several pages during the same pass with no ranking damage.&lt;/p&gt;

&lt;p&gt;Results and honest caveats&lt;/p&gt;

&lt;p&gt;I won't fabricate a hockey-stick chart. What I can say from Search Console:&lt;/p&gt;

&lt;p&gt;Spoke pages that were stuck at positions 10–20 started moving after internal links from an established hub pointed at them — internal linking is the cheapest ranking lever most tool-site builders ignore.&lt;br&gt;
Impressions diversified away from the homepage; the click distribution is less top-heavy than the flat version.&lt;br&gt;
One thing structure can't fix: AI Overviews eating definitional queries. "How many days until X" style informational impressions get answered in-SERP now. Tool intent ("calculate", "calculator") still clicks through. Build for tool intent, not definitions.&lt;/p&gt;

&lt;p&gt;TL;DR&lt;/p&gt;

&lt;p&gt;Model your site as clusters in config, generate links from it — never hand-maintain internal linking.&lt;br&gt;
ISR + client-side calculator widget = crawlable HTML, instant UX, green CWV.&lt;br&gt;
Enrich spokes with tables, FAQs and schema, not word count.&lt;br&gt;
Internal links from hubs are how you unstick pages at positions 10–20.&lt;/p&gt;

&lt;p&gt;The live implementation is at &lt;a href="http://seecalc.com/" rel="noopener noreferrer"&gt;seecalc.com&lt;/a&gt; if you want to click through the cluster structure. Happy to answer questions about the Next.js setup or the GSC data in the comments.&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>seo</category>
      <category>webdev</category>
      <category>sideprojects</category>
    </item>
    <item>
      <title>I Built an AI-Powered Face Shape Detector with Personalized Style Recommendations</title>
      <dc:creator>Naeem Ullah</dc:creator>
      <pubDate>Wed, 01 Apr 2026 04:32:49 +0000</pubDate>
      <link>https://dev.to/enaeemullah/i-built-an-ai-powered-face-shape-detector-with-personalized-style-recommendations-o49</link>
      <guid>https://dev.to/enaeemullah/i-built-an-ai-powered-face-shape-detector-with-personalized-style-recommendations-o49</guid>
      <description>&lt;p&gt;As developers, we often build tools that solve technical problems. This time, I wanted to build something more visual, practical, and fun.&lt;/p&gt;

&lt;p&gt;So I created a &lt;a href="https://faceshapedetector.app/" rel="noopener noreferrer"&gt;Face Shape Detector&lt;/a&gt; — a web app that analyzes a user’s face shape and provides personalized hairstyle, sunglasses, and style recommendations.&lt;/p&gt;

&lt;p&gt;What it does&lt;/p&gt;

&lt;p&gt;The app allows users to upload an image, and it automatically detects their face shape, such as:&lt;/p&gt;

&lt;p&gt;Oval&lt;br&gt;
Round&lt;br&gt;
Square&lt;br&gt;
Heart&lt;br&gt;
Diamond&lt;br&gt;
Rectangle&lt;/p&gt;

&lt;p&gt;After detection, it gives personalized suggestions like:&lt;/p&gt;

&lt;p&gt;Best hairstyles for the detected face shape&lt;br&gt;
Recommended sunglasses/frame styles&lt;br&gt;
Style tips and blog recommendations&lt;/p&gt;

&lt;p&gt;The goal was to make AI-powered style recommendations simple and accessible.&lt;/p&gt;

&lt;p&gt;Tech Stack&lt;/p&gt;

&lt;p&gt;I built this project using:&lt;/p&gt;

&lt;p&gt;Next.js for the frontend and routing&lt;br&gt;
React for UI components&lt;br&gt;
AI / Face Detection Model for face analysis&lt;br&gt;
Responsive UI for mobile and desktop users&lt;br&gt;
Challenges I faced&lt;/p&gt;

&lt;p&gt;One of the biggest challenges was making the detection accurate enough for real-world images.&lt;/p&gt;

&lt;p&gt;Users upload photos with different:&lt;/p&gt;

&lt;p&gt;lighting conditions&lt;br&gt;
face angles&lt;br&gt;
image quality&lt;br&gt;
backgrounds&lt;/p&gt;

&lt;p&gt;Handling these variations while maintaining performance was an interesting problem.&lt;/p&gt;

&lt;p&gt;Another challenge was mapping face shapes to meaningful style recommendations instead of only showing raw AI output.&lt;/p&gt;

&lt;p&gt;Why I built it&lt;/p&gt;

&lt;p&gt;I wanted to combine:&lt;/p&gt;

&lt;p&gt;AI&lt;br&gt;
frontend development&lt;br&gt;
user personalization&lt;br&gt;
practical recommendations&lt;/p&gt;

&lt;p&gt;into a single product experience.&lt;/p&gt;

&lt;p&gt;Instead of just detecting a face shape, I wanted the app to actually help users make decisions.&lt;/p&gt;

&lt;p&gt;Future improvements&lt;/p&gt;

&lt;p&gt;Some ideas I’m planning next:&lt;/p&gt;

&lt;p&gt;beard style recommendations&lt;br&gt;
makeup suggestions&lt;br&gt;
celebrity look-alike comparisons&lt;br&gt;
better AI accuracy&lt;br&gt;
saved style history&lt;/p&gt;

&lt;p&gt;Would love feedback from the DEV community on both the technical and product side.&lt;/p&gt;

&lt;p&gt;What features would you add next?&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>showdev</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
