DEV Community

Kushagra kartikey suman
Kushagra kartikey suman

Posted on

I shipped a SaaS in 5 days at 19 with Next.js 16, Supabase, and Paddle - here's the whole stack

I'm a 19-year-old solo developer who just shipped my first SaaS in 5 days. It's live at https://bountydesk.vercel.app and open source on https://github.com/kushagra1607/bountydesk

This is a no-BS technical breakdown of the stack, every architectural decision, what worked, and what I'd do differently.

The product (1-minute context)

BountyDesk is a submission tracker + Markdown report builder for bug bounty hunters. Free tier; $7/mo Pro. The stack is what this post is about.

The full stack

  • Frontend: Next.js 16 (App Router, Server Actions, Node.js runtime)
  • Styling: Tailwind v4
  • Auth + DB: Supabase (Postgres + RLS + Auth)
  • Billing: Paddle (Merchant of Record - handles tax in 100+ countries)
  • Analytics: PostHog (self-host or cloud, both work)
  • Hosting: Vercel

Monthly cost to run: ~$0. All free tiers.

Architecture decisions

1. Supabase RLS for everything

Every table (submissions, programs, profiles) has Row-Level Security enabled. The policy shape:

create policy "own rows" on public.submissions
  for all using (auth.uid() = user_id)
       with check (auth.uid() = user_id);
Enter fullscreen mode Exit fullscreen mode

A user cannot read or write another user's data, ever, at the database level. Not just app-layer enforcement - Postgres itself blocks it.

Gotcha I hit: my initial profiles table allowed user UPDATE without column restriction. Any user could run UPDATE profiles SET plan='pro' WHERE id=auth.uid() from their browser console - instant free Pro. Caught it in pre-launch audit. Fixed by revoking UPDATE entirely from the authenticated role; only the Paddle webhook (service_role) can write.

2. Paddle as Merchant of Record

I'm in India. Selling globally means VAT in 27 EU countries, GST in Australia, etc. Paddle is a Merchant of Record - they take legal/tax responsibility. I just receive a payout in INR.

Fee: 5% + $0.50 per transaction. On a $7/mo subscription, I see ~$6.15 in my Paddle balance, ~$6.00 after Payoneer FX → INR.

3. Webhook signature verification

The webhook handler verifies the Paddle HMAC signature on the raw body (before any parsing):

const signature = request.headers.get("paddle-signature") ?? "";
const body = await request.text();

try {
  const event = await getPaddle().webhooks.unmarshal(
    body, secret, signature
  );
} catch {
  return NextResponse.json({ error: "bad signature" }, { status: 400 });
}
Enter fullscreen mode Exit fullscreen mode

If you parse the body first (request.json()), Node mutates whitespace and signature check fails. Always read raw text first.

4. PostHog → Slack for real-time alerts

PostHog has CDP (Customer Data Platform) functions that fire actions on event matches. I have three:

  • user_signed_up → Slack: "New signup!"
  • upgrade_checkout_opened → Slack: "Upgrade clicked!"
  • subscription_activated (fired server-side from the Paddle webhook) → Slack: "PAYMENT RECEIVED!"

I literally know the moment a customer pays before Paddle even shows it in their dashboard.

5. AGPL-3.0 license

Open source with a viral copyleft. If someone forks the code, modifies it, and runs it as a competing SaaS, they must open-source their changes too. Same license PostHog, Plausible, and Cal.com use.

What I'd do differently

  1. Start the HN account age clock 30 days BEFORE launch. HN auto-flags new-account Show HN posts. Learned this the hard way.
  2. Build distribution while you build the product. I shipped the code in 5 days but spent 0 days on Twitter or community. By launch day I had no audience to broadcast to.
  3. Get a real domain. vercel.app subdomain looks indie-ish. ~$10/year for bountydesk.com would have signaled "real product."
  4. Open source from day 1, not day 30. Stars and contributions compound.

What I'd repeat

  1. Paddle. Selling globally on day 1 with no compliance burden is magical.
  2. Supabase RLS. Catches what app-layer code forgets.
  3. PostHog + Slack alerts. Real-time visibility into every conversion.
  4. Vercel free tier. Zero deploy friction.

The code

All ~70 source files on GitHub: https://github.com/kushagra1607/bountydesk

Interesting files:

  • src/app/api/paddle/webhook/route.ts - webhook + signature verification
  • src/lib/supabase/admin.ts - server-only service-role client
  • supabase/schema.sql - full schema with RLS policies
  • src/components/ReportBuilder.tsx - the report generator

Try it

Live: https://bountydesk.vercel.app

Sign up, log a fake submission, tell me what sucks. I respond to all DMs/comments.

— Kushagra (@bountydesk on X)

Top comments (0)