Dev.to WebDev 🛠 Dev 👁 0 📖 6 min read

How I got ~500k organic search clicks with a vibe-coded app: the architecture, phase by phase

Originally published on my blog. A note before starting: this post is not written by AI, but the diagrams were generated with AI. Since the introduction of early AI tools, I have been really into using them actively, b

How I got ~500k organic search clicks with a vibe-coded app: the architecture, phase by phase

Originally published on my blog.

A note before starting: this post is not written by AI, but the diagrams were generated with AI.

Since the introduction of early AI tools, I have been really into using them actively, both for my professional career and in my free time, to try to catch up with their evolution (which, as everybody here knows, is pretty hard to do). As a result, I vibe-coded a web application (100% vibe-coded) for astrological calculations. Bear in mind I have zero knowledge of astrological math and calculations, so I should give AI tools good credit for that.

Initially, Cursor was my IDE to vibe-code and Claude was the primary LLM to write the code. As the application got real users I had to roll up my sleeves, since this app needed to scale and AI felt short on architectural decisions. Plus, as you know, I'm obsessed with web performance, so I wanted to see how far I can go combining my skills with AI.

This post dives deep into this project's architecture.

Early architecture

Technical

Early technical architecture: a Next.js app with client-side calculations, an open-source places API for location search and Supabase for feedback

Early technical architecture

The app was running on a fully Next.js platform with client-side calculation methods, an open-source places API for location search, and user comments and feedback saved into a free-tier Supabase. A user types in their information, client-side calculations produce the result, the user gets it and leaves. Sounds smooth and easy. It was mostly vibe-coded: I set up my Cursor files very well, and the skills and commands work so well that I one-shot each new calculator page. Life is good.

Content

Early content architecture: AI writes content, Sanity Studio stores it, a webhook triggers a fresh build

Early content architecture

For content I use the Sanity Studio free-tier plan, and it's enough because all of my pages are SSG'ed (statically generated at build time, so I query Sanity only when my Next.js app rebuilds). AI writes my content, I publish it, a Sanity webhook triggers my deploy, and I get a fresh build with fresh content. Sanity Studio is cloud-hosted by Sanity, which is included in the free plan.

Phase 1: ~5K monthly users

The app is running on the free-tier Vercel plan and nothing breaks.

Another challenge at this step was the free places API's limits. For an astrological calculation app, location search is essential: location input is required for almost every calculation. I solved this with Redis (Upstash) for my place searches, so I didn't query the free API that often. It solved my problem at this step, but Upstash Redis itself has a free-tier limit too, just harder to hit than the location API's.

Phase 1 architecture: Redis in front of the places API

Phase 1 architecture

I decided to add more pages to grow my audience, and as the audience grew I wanted to move to a more professional setup. It was not a must in this phase, but a preparation for future traffic spikes. So I moved my app to AWS Amplify, with CloudFront for security.

This is also the phase where I started to dive deep into the app's performance. I constantly analyzed the bundle size, optimized the codebase, and ran dead code detection (knip is very useful). I added a JavaScript performance observer that logs users' metrics to my Supabase database, and built a dashboard on that data to monitor user metrics, rather than using ready-made tools like Sentry or New Relic. Monitoring RUM (real user metrics) will surprise you, as you will clearly see that users do not have fast devices :) And for ranking higher on Google you need to serve a good user experience, so it became an obsession at this point. I simplified all the components, removed heavy UI component libraries, lazy-loaded the birth chart library to get it out of the bundle, and so on. It's also hard to believe how many users are still on very slow devices.

Web performance is not something you can focus on, solve and forget. It is something you need to consider and monitor constantly.

Search Console Core Web Vitals report for mobile: 229 URLs rated good, none poor or needing improvement

Google Search Console, Core Web Vitals report for mobile: 229 URLs rated good, none poor or needing improvement.

Phase 2: ~10K monthly users

AWS Amplify ran smoothly, but the Lambda functions and CloudFront started to get costly, and I have no monetization plan other than Google AdSense. I didn't want to give it all back to AWS.

Phase 2 architecture on AWS Amplify and CloudFront

Phase 2 architecture

Another challenge with AWS: I had published more than ~200 pages to this application for organic SEO, and I hit the wall of bundle size. Platforms like AWS Amplify and Vercel only allow a bundle of 200 MB, and since I'm SSG'ing all my pages, my bundle grew larger than that. So I had to find a way.

Phase 3: ~30K monthly users

I decided to move away from AWS and host the app on an Ubuntu VPS with Coolify, so the bundle size limit disappeared. Now I can statically generate as many pages as I want. Plus, it's a lot cheaper.

Cloudflare Web Analytics for burcapp.com over the last 24 hours: 1.54k visits, 3.92k page views, 97% of LCP measurements good

Cloudflare Web Analytics for the project, last 24 hours, bots excluded.

For caching I use Cloudflare, which offers a generous quota, and I cache all the requests hitting my VPS aggressively, which has also improved my Lighthouse metrics. I have a cache purge method that runs against Cloudflare whenever a new deploy or a content change happens.

Phase 3 architecture at 30k users: VPS with Coolify behind Cloudflare

Phase 3 architecture, 30k users

I added a user review form to the application to get feedback from users. Very often I got messages saying the calculations were giving wrong results. In the end it is vibe-coded, and you know how it is. The next challenge at this point was the inconsistency of the astrological results. I did some research and found the issue. Remember that our calculations were done in the client's browser with client-side JavaScript. Therefore the calculations differed from device to device, and the time zone handling was not consistent.

Another reason was that there are a lot of libraries that provide planets' positions, and the one I had been using was neither very popular (there are different techniques to calculate the result, and some of them are more popular and preferred) nor used by professional astrological calculators.

Plus, at this point I had decided to create a mobile app for the app stores, and I wanted web and mobile to give the same results. Client-side calculations weren't enough for a consistent app.

Phase 4: an API for my web and mobile apps

Professional planet-position libraries are licensed. But luckily there is a good Python community that provides the same data as open source, so I deployed a Python API. Only my Node.js server can query it. I got 98% correct calculations when compared to professional paid libraries. And with my own API I can now provide correct calculations to my multi-platform apps.

A strict orchestration of Claude helped me develop this robust and precise API. I now have an orchestration workflow all the way from planning to UAT testing.

Another benefit of separating the calculations into their own API is that my Next.js app's INP scores have remarkably healed, as it has become less dependent on browser scripting.

You can view the site at burcapp.com.

Phase 4 architecture: web and mobile apps call a Node.js server, which is the only client of the Python astrology API

Phase 4 architecture, API

Finally

It has been a good side project that taught me a lot about vibe-coding and about handling a web application with real users end to end. I started this project to practice with AI 15 months ago. Back then I used Cursor for coding and now I'm on Claude. The LLMs I have been using have gotten remarkably better since then.

Take the claude-seo skill for instance. It is a very powerful tool to quickly scan your pages across many different aspects of SEO, report what you are missing, and help you improve your organic traffic.

I have learned a lot about AI from this project. Looking back at where I started, I have come a long way: I learned how to orchestrate agents, create rules and commands, when to use skills and when to delete rules, and so on. I came to this conclusion:

Google Search Console, last 12 months of web search: 481K clicks, 4.23M impressions, 11.4% average click-through rate, average position 7.6

Google Search Console result for the last 12 months: 481K clicks and 4.23M impressions. The interface is in Turkish, where "B" means thousand and "Mn" means million.

You can't vibe-code an app and expect people to use it without giving a thought to what it is really building. However, if you know what you are doing, AI is a very powerful tool to improve productivity, and its outcome is getting much better every day.

📰 Read the original article on Dev.to WebDev

Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.