All Startup Ideas

Feature Voting Board

Public roadmap + feature voting for indie SaaS. Flat pricing, embeddable widget, AI dedup. Undercuts Canny. Weekend MVP guide + prompts.

A SaaS founder gets feature requests in every channel at once. Twitter DMs. Intercom. Slack Connect threads. Email forwards from the CEO. Postmortem docs from customer interviews. One engineer maintains a Notion page called "Roadmap Ideas (actual)" that nobody trusts. By the time the team picks a quarterly theme, half the requests have gone stale and the other half were from one loud user who never actually upgrades. The incumbent answer is Canny at $360/month plus per-member pricing. That is a rounding error for a Series A company and a deal-breaker for the indie SaaS at $3K MRR. Founders who cannot justify Canny's price end up hand-building a Trello board, inheriting a dusty UserVoice subscription, or maintaining a GitHub issues repo labeled "public." None of these surface signal.

Built for Developers, Solo Founders.

Suggested stack: Next.js 14 App Router, Supabase, Claude Haiku 4.5 for dedup, Upstash Redis rate limits, Resend + custom domain, Stripe Billing + Vercel. Weekend scope: about 8 hours.

The Problem

A SaaS founder gets feature requests in every channel at once. Twitter DMs. Intercom. Slack Connect threads. Email forwards from the CEO. Postmortem docs from customer interviews.…

The Solution

A multi-tenant feature-voting SaaS priced for the indie and small-team segment. Each customer gets a public board at their own subdomain (or custom domain on paid tiers), an…

Market Research

Canny has 1,000+ paying teams (public ARR estimates ~$10M+). It was acquired by Permanent Capital in 2024 — a clear exit validation of the category at scale. Their pricing at…

Competitive Landscape

Canny — Category leader for SaaS feature voting. Deep Intercom/Slack integrations, polished admin. Acquired by Permanent Capital 2024. Per-user-per-month pricing adds fast; custom…

Business Model

Free ($0) — 1 board, 100 total submissions, subdomain only, “Powered by” footer

Recommended Tech Stack

Next.js 14 App Router — Middleware routes `tenantSlug.product.com` or custom domain to `/[tenantSlug]/board`. Server Actions for vote/submit. Public board pages as Server…

AI Prompts to Build This

Copy these build prompts into Claude, Cursor, or your AI coding tool. Create a free account to unlock the full research behind them.

  1. 1. Multi-Tenant Scaffold

    Create a Next.js 14 App Router multi-tenant SaaS for a feature voting board. Supabase backend, Tailwind, TypeScript.
    
    Schema (Supabase Postgres):
    - tenants(id, slug, custom_domain, owner_user_id, brand_primary_hex, stripe_customer_id, plan ENUM[free,pro,team], created_at)
    - features(id, tenant_id, title, body, status ENUM[under_review,planned,in_progress,shipped,wontfix], vote_count INT, created_by_email, created_at, shipped_at)
    - votes(id, feature_id, voter_email, voter_ip, created_at) — unique(feature_id, voter_email)
    - comments(id, feature_id, body, author_email, author_role ENUM[public,admin], created_at)
    - subscribers(id, feature_id, email) — voters who want status update emails
    
    RLS: tenants own-row; features/votes/comments scoped by tenant_id; public read on non-deleted rows.
    
    Middleware (Next.js):
    - Inspect request Host. If host matches tenants.custom_domain OR {slug}.portal.product.com, rewrite to /[tenantSlug]/board/...
    - If host is app.product.com, render admin routes at /admin/...
    
    Routes:
    - /[tenantSlug]/board (public list, filter by status, sort by votes|newest)
    - /[tenantSlug]/f/[featureId] (detail + comments)
    - /admin/login
    - /admin/features (triage view: new submissions, pending dedup, status changes)
    - /admin/settings (domain, branding, billing, integrations)
    
    Use Server Actions for the /vote and /submit mutations; include revalidatePath on the public board.
  2. 2. AI Dedup + Rate Limiting

    Implement AI-powered duplicate detection and vote spam protection. This is the product's differentiation vs Canny/Nolt.
    
    Dedup flow on submission:
    1. User submits new feature via /submit Server Action.
    2. Run Postgres FTS against existing features for this tenant: SELECT id, title, body, vote_count, ts_rank(to_tsvector(title || ' ' || body), websearch_to_tsquery($query)) AS rank FROM features WHERE tenant_id=$tid AND status NOT IN ('shipped','wontfix') ORDER BY rank DESC LIMIT 10;
    3. If top candidate rank > 0.3, pass the submission + top 5 candidates to Claude Haiku 4.5:
     System prompt: "You identify whether a new feature request is a duplicate of existing ones. Return JSON: {is_duplicate: bool, match_id: string|null, confidence: 0-1, reason: string}"
    4. If is_duplicate AND confidence > 0.7: show user the modal: "This looks similar to [existing feature]. Vote for it instead?" with [Vote existing] or [Submit anyway].
    5. If user confirms submit anyway, create new feature. Track the "declined dedup" rate as a product metric.
    
    Rate limiting via Upstash Ratelimit:
    - Votes: 1 per (feature_id, voter_email) — DB unique constraint.
    - Submissions: 20/day per tenant (stop spam) and 5/hour per voter_email.
    - IP-based: 100 requests/hour per IP per tenant to the /vote and /submit endpoints.
    - Return 429 with Retry-After header when exceeded.
    
    Cost: Haiku dedup costs ~$0.002 per submission; budget-safe even at 10K submissions/month ($20).
  3. 3. Embeddable Widget + Status Notifications

    Build the embeddable widget and the status-change notification loop. These close the retention flywheel.
    
    Embeddable widget:
    - Host a standalone JS bundle at https://cdn.product.com/widget.js. Customer pastes:
    
    - On load, create a floating button ("💡 Feedback") in bottom-right.
    - Click opens an iframe pointing to https://acme.portal.product.com/widget (sandboxed with allow="forms").
    - Inside the iframe, render a trimmed version of the board: list top 10 active features, submit button, search.
    - postMessage bridge: if the host app wants to pass user_email (for pre-auth), the parent calls window.postMessage({type: 'identify', email: '...'}, '*') and the widget iframe listens. Reduces submission friction to one click.
    - Widget HTML/CSS: Tailwind inlined, 50KB total, zero dependencies on host app.
    
    Status-change notifications:
    1. Admin changes feature status in /admin/features. Server Action writes new status + records the prior one.
    2. Enqueue a background job (Vercel Cron or Upstash QStash): "send status-change emails for feature_id=X."
    3. Job queries all (voters + subscribers) for that feature, dedupes emails.
    4. Send via Resend using tenant's sender domain (Team tier) or platform domain (Free/Pro). React Email template with the feature title, new status, tenant branding.
    5. Track open + click via Resend webhooks; store as analytics.status_email_opens for the admin dashboard.
    6. For shipped status: auto-generate a changelog entry at /[tenantSlug]/changelog with markdown body. Team tier can toggle "auto-publish to changelog."
    
    This is the retention flywheel: voters get re-engaged on every ship event, admins get free proof-of-shipping marketing, and dormant accounts reactivate when a feature they cared about goes live.