I built a "feedback management tool" for collecting customer requests entirely on Cloudflare's own services, as a solo project. It's called Feedury. This post focuses on the technical side: what I built, why I chose this stack, and where I ran into trouble.
What I built
A tool where customers submit requests, react with votes and comments, and requests get tracked through statuses (open, planned, in progress, done) on a public board. I started building this kind of tool because most existing request-management setups I'd seen stopped at "tally up the count." I wanted to build a way to capture the "why" behind the count directly into the product (I wrote more about this way of thinking in "Counting Feature Requests Won't Tell You What to Build Next").
The stack
The backend runs on Hono, deployed to Cloudflare Workers as a single Worker. No microservices: routing and every screen live in one Worker. As a solo developer, I didn't want to pay the operational cost of running multiple services.
For the frontend, I skipped an SPA framework. It's a server-rendered multi-page app (MPA), with htmx layered on top only where something needs a partial update, like updating a vote count after someone clicks the vote button. htmx handles that level of interactivity just fine. There's no build step, so deploying is a single command:
wrangler deploy
As a solo project, not having to worry about "the build broke and I have to fix it at 2am" is a real relief.
The database is Cloudflare D1 (SQLite) end to end. No KV; even session storage lives in D1. IDs use ULIDs, and aggregate values like vote counts are kept as denormalized counters rather than recomputed with a JOIN each time. Migrations skip an ORM in favor of plain SQL files applied with:
wrangler d1 migrations apply featury-db --remote
The table count is small enough that an ORM's abstraction cost would outweigh the benefit.
AI features run entirely on Cloudflare Workers AI, no external LLM API. Summaries use a lightweight Llama-family model, and similarity between posts uses an embedding model with cosine similarity computed brute-force at request time. I skipped a dedicated vector search backend (Vectorize). At the current post volume, brute-force is fast enough, and there wasn't yet a clear benefit to adding dedicated infrastructure; something I'll revisit as data grows.
Email is the one external SaaS dependency: Resend. Cloudflare has recently introduced its own email sending option (Email Service, in public beta), but sending to arbitrary recipients currently requires Workers Paid. For now I'm using Resend's free tier, which covers current volume, and keeping Email Service as a migration target for later.
What was hardest to get right
The AI summaries and the post-submission follow-up question took the most iteration. My first idea was to ask a question before someone submitted anything, but that makes the very first step, writing the request, feel heavier. What I landed on: save the post first, then on the very next screen, ask a short "tell us a bit more" question with a few quick-pick options plus a free-text field. Answering is optional; skipping it doesn't affect whether the post itself goes through.
The other hard part was how to feed "product context" into the summaries. The same "search is slow" post means something different depending on what the product actually does. I added a place in the admin dashboard to describe the product's context (target users, the problem it solves, key features) and feed that into the AI prompt.
Why "reasons," not just "counts"
Most request-collection tools rank things by vote count or volume. That's useful, but it doesn't tell you whether to build the thing with 10 votes or the thing with 3 votes and a serious underlying reason first. In practice, that decision usually falls to someone reading through each request by hand and guessing at the reasoning.
In Feedury, AI summarizes who's affected, what's frustrating them, and why they want it at the moment someone posts, and groups similar posts so you can see the combined empathy behind them. The goal was to still aggregate, but not stop at aggregating.
If you want to try it
There's a demo board you can try with no signup: a fictional task management SaaS with real posts, statuses, and votes to look at. Every feature is free to use right now, and no credit card is required.
Closing thoughts
Leaning on Cloudflare was mostly about keeping costs low, but it was also useful to confirm that Workers, D1, Workers AI, and Hono together are enough to build a working SaaS, from auth through AI features. Hope this is useful if you're thinking about building a SaaS product solo.