Prisma + PostgreSQL · Polar.sh Checkout · 5 min read

Prisma + Polar

Prisma schema with Polar checkout for creator tools.

Copy-paste this into Cursor, Claude, or Codex to scaffold a pay-to-rank board like ihatereading.lol.

In this stack

The prompt

Official docs, keys, and adapter rules the agent should follow.

Follow official docs only. Use the URLs, npm packages, and key locations in PLATFORM DETAILS. Do not invent SDK method names — look them up from those links.

Next.js + shadcn + Tailwind

OFFICIAL LINKS (open and follow these — do not invent APIs)

NPM PACKAGES

  • next
  • react
  • tailwindcss
  • class-variance-authority
  • lucide-react

API KEYS — name and exactly where to create them

SETUP STEPS

npx create-next-app@latest . --ts --tailwind --app --src-dir
npx shadcn@latest init
npx shadcn@latest add button input card badge

Prisma + PostgreSQL

OFFICIAL LINKS (open and follow these — do not invent APIs)

NPM PACKAGES

  • prisma
  • @prisma/client

API KEYS — name and exactly where to create them

  • DATABASE_URL: Postgres connection string from Neon, Vercel Postgres, Supabase, or Railway. prisma+postgres://... or postgresql://...

SETUP STEPS

  1. Create a Postgres database (Neon is fastest: https://console.neon.tech)
  2. Copy the connection string → DATABASE_URL
  3. npx prisma init && define Listing, Bid, PendingCheckout
  4. npx prisma migrate dev --name init

Polar

OFFICIAL LINKS (open and follow these — do not invent APIs)

NPM PACKAGES

  • @polar-sh/sdk
  • @polar-sh/nextjs

API KEYS — name and exactly where to create them

  • POLAR_ACCESS_TOKEN: Polar org settings → Organization Access Token (polar_oat_… or polar_pat_…). Server only.
  • POLAR_WEBHOOK_SECRET: Org settings → Webhooks → Add endpoint → generate signing secret
  • POLAR_PRODUCT_ID: Products → create a one-time product → copy the product id
  • POLAR_SERVER: Optional. sandbox vs production. See Polar Next.js guide.

SETUP STEPS

  1. https://polar.sh → create organization (use sandbox while building)
  2. Org settings → create Organization Access Token → POLAR_ACCESS_TOKEN
  3. Products → one-time product, min $1 → POLAR_PRODUCT_ID
  4. Settings → Webhooks → Add Endpoint → {SITE}/api/webhooks/polar → copy secret → POLAR_WEBHOOK_SECRET
  5. Subscribe to order.paid (and checkout events you need)
  6. Local tunnel: polar listen http://localhost:3000/ (https://polar.sh/docs/integrate/webhooks/endpoints)
  7. Put pending_id in checkout metadata

You are scaffolding a pay-to-rank bidding board (same product as ihatereading.lol).

PRODUCT

A public leaderboard. Anyone pastes a URL (or listing), types a bid of $1+, pays, and that listing rises by CUMULATIVE money. Highest total bid is #1. No user accounts. Anonymous is fine.

USER JOURNEY

  1. Land on / — hero + bid form + live board
  2. Paste URL → preview title/image/description (Open Graph)
  3. Set bid (number stepper, min $1 / 100 cents). Default the input to the current highest board bid.
  4. Pay → redirect to provider checkout
  5. Return /success?checkout_id=... → poll status until live → show rank + confetti
  6. Board shows rank, thumbnail, title, total $, bid count. Click a row → /listing/[id] to add another bid (stack).

DOMAIN (use these names, do not invent a different model)

  • listings: id, url, type, title, description, thumbnail_url, favicon_url, author_name, submitted_by_name, total_bid_cents, bid_count, bid_cents_last_24h, status (pending|live|rejected), created_at, last_bid_at
  • bids: id, listing_id, amount_cents, bidder_name, provider, checkout_id, payment_id, customer_email, created_at
  • pending_checkouts: id, url, preview fields, bid_amount_cents, existing_listing_id (null = new URL), provider_session_id, created_at
  • Optional: presence + stats counters for "N online" / views

RULES (must implement)

  • Min bid $1 (400 if amount_cents < 100)
  • Normalize URLs (https, strip tracking params). Same URL cannot create a second listing — return 409 with existing_listing_id; user must stack a bid instead
  • Stacking: paying against existing_listing_id adds amount to total_bid_cents and bid_count
  • Rank all-time: ORDER BY total_bid_cents DESC, last_bid_at DESC
  • Rank trending: ORDER BY bid_cents_last_24h DESC
  • Payments are idempotent: never insert the same payment_id twice
  • Flow: create pending_checkout → create provider checkout with metadata { pending_id, bid_amount_cents } → webhook OR success-page poll fulfills → create/update listing + insert bid
  • Server-only writes for money (never let the browser increment totals)
  • No auth required
  • Admin page optional: password gate to reject a listing

PAGES

  • / landing (form + board)
  • /listing/[id] detail + stack bid + bid history
  • /success payment confirmation
  • /stats simple counters
  • shadcn/ui + Tailwind. Light theme. Mobile-first: stack board cards on small screens.

APIS

  • POST /api/preview { url }
  • POST /api/checkout { url, preview, bid_amount_cents, existing_listing_id? }
  • GET /api/status?checkout_id=
  • POST /api/webhooks/[provider]
  • GET /api/board?sort=all_time|trending

SHIP

  • .env.example with every key AND a comment above each key: what it is + the exact dashboard URL to create it
  • README: numbered setup using the PLATFORM DETAILS links below
  • Seed + clear scripts
  • TypeScript strict. Do not add extra features (auth, AI ranking, comments).

STACK (do not substitute)

  • Next.js 14+ App Router, TypeScript, Tailwind CSS, shadcn/ui, React Query or SWR
  • Database: Prisma + PostgreSQL
  • Payments: Polar.sh Checkout

ADAPTER RULES

Same Prisma models. Polar checkout + webhook verification.

paymentId unique on Bid. Transactional increment on Listing.

ENV KEYS for .env.example (comment each with the dashboard URL from PLATFORM DETAILS)

  • NEXT_PUBLIC_SITE_URL
  • DATABASE_URL
  • POLAR_ACCESS_TOKEN
  • POLAR_WEBHOOK_SECRET
  • POLAR_PRODUCT_ID

Copy every official link from PLATFORM DETAILS into README.md under Setup.

Build the complete runnable app now. After files exist, print: install, env, migrate/seed, webhook listen, npm run dev.