October 2, 2026 · 2 min read · Manikandan V

Build log — a live ranking table on SvelteKit and Cloudflare

The architecture behind HuntedTools, why we did not fork EmDash, how one SQL schema serves software and hammers alike, and what we do to keep fake reviews out.

HuntedTools is a single SvelteKit app deployed to Cloudflare Workers with D1 as the database. This post is for the curious and for anyone building something similar.

Why not EmDash?

Cloudflare's EmDash is a lovely WordPress successor, but it is built on Astro and shaped around posts and pages. Our core object is not a post — it is a tool with live, per-user signals, and the entire site is one giant sortable table. Bolting that onto a CMS would have meant fighting it. We kept the idea we liked (markdown content, edge deployment) and wrote the ranking engine ourselves in SvelteKit. The blog you are reading is plain markdown files compiled at build time.

One schema for everything

A hammer and a code editor share more than you would think: a name, a tagline, a category, a price, a rating, and a set of signals. The tools table holds the shared fields; kind says whether it is a web app, desktop software, a physical product or a service. Categories are a two-level tree that admins edit in the browser. Metrics — the signal columns — live in their own table with a scope, so "Built to Last" can exist only for physical tools while "Must Have" exists everywhere.

The live table

The ranking table is server-rendered on first load for SEO and speed, then hydrates and polls for changes every twenty seconds. Votes are optimistic: tap a signal and the count moves instantly; if the server disagrees, it rolls back. Sorting by any metric is a real SQL sort, so page two is correct too.

Search uses SQLite FTS5 — both locally and on D1 — with prefix matching so results appear as you type.

Keeping it honest

  • Google sign-in for anything that writes. Searching needs no account.
  • One signal per person per tool per metric, enforced by a unique index.
  • Submitters cannot vote on or review their own listings.
  • Rate limits on submissions, votes and reviews.
  • A honeypot field on the submit form, a report button on everything, and an events log that lets us spot vote bursts.

What is next

Durable Objects for true push updates instead of polling, image uploads to R2, and an open API so other sites can embed a board. If you want to help, the whole thing is TypeScript and the formula is documented.

Sign in to hunt

  • One Google account = one voice. No bought reviews, no bots.
  • Searching and browsing never needs an account.

Sign-in isn't configured on this deployment yet.