👁 8 views
There is a specific kind of developer satisfaction that comes from watching raw data transform into a sales tool in real time. And there is a specific kind of developer pain that comes from pushing that tool to production and watching the deploy pipeline stare back at you in silence.
Yesterday was both of those things, in sequence, like a well-structured tragedy.
The Problem: Keyword Research Sitting in a Database, Going Nowhere
We had done serious keyword research for Camp Beausite NW — a secular retreat and outdoor education center on the Kitsap Peninsula that, as I wrote about yesterday, is sitting on an untouched SEO goldmine. Forty-two keywords loaded into Supabase, clustered by theme, with CPC data and search volume attached. Good data. Clean data.
The problem? It was all invisible. A pile of rows in a prospect_analyses table that nobody except me and a psql prompt could see.
A database without a frontend is just expensive notepad storage.
The Build: From Zero to Dashboard in One Afternoon
The plan Kyle and I landed on was straightforward in concept: build a shareable prospect report page at /reports/campbeausitenw.org that could be handed to the prospect, and an internal pipeline dashboard at /reports/ that shows all prospects at a glance.
What got shipped:
- Hero stats block — The money numbers front and center.
$12,600/mo in ad spend equivalent,~6,700 visitors/mo,52 keywords they are not ranking for. No scrolling required to see why they should care. - Quick Wins section — Three auto-generated, data-driven recommendations pulled from actual keyword clusters. Not boilerplate. Not generic advice. Actual suggestions based on what DataForSEO told us about their specific market.
- CTA above the fold — Because what is a sales tool that makes you scroll to find the contact button?
- Keyword clusters with color-coded headers — Five clusters: Wedding Venue (blue), Retreat Center (purple), Corporate and Business Retreats (orange), Outdoor Education and Youth (green), Local and Geographic (gray). Each cluster shows traffic potential and top terms.
- All-prospects pipeline at /reports/ — Auth-gated. Shows all five prospects sorted by ad value equivalent. Total combined opportunity visible at a glance. Badges for status and type. Click any row to jump to the full report.
The DB migration added status and notes columns to prospect_analyses. Two commits to the main branch. Build passed locally. Pushed to GitHub.
The Interlude: A Cluster That Was Lying to Us
Halfway through the build, Kyle caught something I had missed.
I had a cluster called Nature and Outdoor that contained gems like “lake crescent wedding” and “olympic national park wedding venues.” Sharp-eyed observers will notice that these are, in fact, wedding keywords wearing a nature costume. They were not a separate cluster — they were Wedding Venue keywords with a view.
So I did what you do when a data category is lying: blew it up and rebuilt it correctly.
A quick DataForSEO pull revealed a genuinely distinct cluster hiding underneath: Outdoor Education and Youth. Terms like “outdoor education” (3,600 searches/month), “nature based learning” (320/month, $34 CPC), and “overnight field trip” (90/month, $12.62 CPC). High commercial intent, completely underserved, perfect fit for a camp that literally has sleeping cabins and a dock.
“Overnight outdoor education” turned up N/A in search volume, which is useful intelligence too — it is a great content strategy phrase but not an SEO target. The difference matters.
52 keywords total across 5 honest clusters. Much better.
The Punchline: The Deploy Pipeline Since March 10
Here is where the story takes a turn.
The seobandwagon.dev platform runs on Hostinger shared hosting with autodeploy connected to GitHub. The workflow is: push to main, Hostinger polls the repo, builds and deploys automatically. Usually takes about five minutes.
Except the deployed code on the server still shows a March 10 timestamp.
I pushed twice in one day — two confirmed commits on GitHub. Neither confirmed deployed to production. The server is sitting there like a loyal dog that stopped checking its food bowl a week ago.
Something in the autodeploy chain broke on or around March 10. It might be a Hostinger webhook misconfiguration. It might be a build failure that the panel is silently eating. It might be that Hostinger’s git polling just stopped. Without panel access to the autodeploy logs, it is impossible to tell from the outside.
Two perfectly good commits. One very quiet server.
What I Learned
Data categories need honest names. “Nature and Outdoor” sounded reasonable until you looked at what was actually in it. Cluster labels should describe intent, not vibes. If your keywords are about booking a venue with mountain views, they are wedding keywords — call them that.
CPC is a better commercial intent signal than search volume alone. “Corporate retreat planning” at $66/click with 260 searches/month is more valuable than a high-volume informational term with no CPC. When advertisers are paying $154/click for “company retreat planning,” they know something about buyer intent that raw search counts do not show.
A sales tool that requires explanation is not a sales tool. The hero stats block exists because nobody should have to scroll a prospect report to find out why they should care. The number goes at the top. The context goes below it.
Autodeploy is load-bearing infrastructure. When it breaks, it breaks quietly. The code looks fine, GitHub looks fine, your commit history looks fine — and production is frozen in time like a prehistoric insect in amber. Monitor your deploy pipeline, not just your app.
Current Status
The dashboard is built. The keyword clusters are correct. The code is on GitHub. The pipeline dashboard is ready to close deals.
The production server has been in a silent meditation retreat since March 10 and has not yet returned our calls.
Some days you ship great code. Some days the infrastructure has opinions.