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)
- Next.js App Router: https://nextjs.org/docs/app
- Route Handlers: https://nextjs.org/docs/app/building-your-application/routing/route-handlers
- Environment variables: https://nextjs.org/docs/app/building-your-application/configuring/environment-variables
- shadcn install (Next.js): https://ui.shadcn.com/docs/installation/next
- shadcn components: https://ui.shadcn.com/docs/components
- Tailwind v3 + Next.js: https://v3.tailwindcss.com/docs/guides/nextjs
- Vercel deploy: https://vercel.com/docs/getting-started-with-vercel
- Vercel env vars: https://vercel.com/docs/projects/environment-variables
NPM PACKAGES
- next
- react
- tailwindcss
- class-variance-authority
- lucide-react
API KEYS — name and exactly where to create them
- NEXT_PUBLIC_SITE_URL: Your public origin, e.g. http://localhost:3000 or https://yourdomain.com
SETUP STEPS
npx create-next-app@latest . --ts --tailwind --app --src-dir npx shadcn@latest init npx shadcn@latest add button input card badge
Convex
OFFICIAL LINKS (open and follow these — do not invent APIs)
- Convex Dashboard: https://dashboard.convex.dev
- Next.js quickstart: https://docs.convex.dev/quickstart/nextjs
- HTTP actions / webhooks: https://docs.convex.dev/functions/http-actions
- convex npm: https://www.npmjs.com/package/convex
NPM PACKAGES
- convex
API KEYS — name and exactly where to create them
- CONVEX_DEPLOYMENT: Created by npx convex dev (written to .env.local)
- NEXT_PUBLIC_CONVEX_URL: Convex Dashboard → Settings → URL, or from npx convex dev
SETUP STEPS
- https://dashboard.convex.dev → create project
- npx convex dev (writes CONVEX_DEPLOYMENT + NEXT_PUBLIC_CONVEX_URL)
- Money writes only from mutations called by the Stripe webhook / httpAction
Stripe
OFFICIAL LINKS (open and follow these — do not invent APIs)
- Stripe Dashboard: https://dashboard.stripe.com
- API keys: https://dashboard.stripe.com/apikeys
- Webhooks: https://dashboard.stripe.com/webhooks
- Checkout Sessions: https://docs.stripe.com/payments/checkout/how-checkout-works
- Create a Checkout Session API: https://docs.stripe.com/api/checkout/sessions/create
- stripe npm: https://www.npmjs.com/package/stripe
- Stripe CLI (local webhooks): https://docs.stripe.com/stripe-cli
- Test cards: https://docs.stripe.com/testing#cards
NPM PACKAGES
- stripe
API KEYS — name and exactly where to create them
- STRIPE_SECRET_KEY: https://dashboard.stripe.com/apikeys → Secret key (sk_test_… locally, sk_live_… in prod). Server only.
- NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY: Same page → Publishable key (pk_test_…). Only if you use Stripe.js; Checkout redirect can skip it.
- STRIPE_WEBHOOK_SECRET: https://dashboard.stripe.com/webhooks → Add endpoint → Signing secret (whsec_…). Locally: stripe listen --forward-to localhost:3000/api/webhooks/stripe
SETUP STEPS
- https://dashboard.stripe.com → sign up, stay in Test mode
- Developers → API keys → STRIPE_SECRET_KEY
- Create Checkout Session: mode=payment, line_items price_data.unit_amount = bid cents, metadata.pending_id
- Success URL: {SITE}/success?checkout_id={pending_id}
- Webhook endpoint: {SITE}/api/webhooks/stripe event checkout.session.completed
- Local: stripe listen --forward-to localhost:3000/api/webhooks/stripe → STRIPE_WEBHOOK_SECRET
- Test card: 4242 4242 4242 4242
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
- Land on / — hero + bid form + live board
- Paste URL → preview title/image/description (Open Graph)
- Set bid (number stepper, min $1 / 100 cents). Default the input to the current highest board bid.
- Pay → redirect to provider checkout
- Return /success?checkout_id=... → poll status until live → show rank + confetti
- 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: Convex
- Payments: Stripe Checkout
ADAPTER RULES
Convex tables for listings/bids/pending. Mutations only from Convex httpActions / Next webhook that calls an internal mutation.
Stripe Checkout. Board uses useQuery so ranks update live after pay.
ENV KEYS for .env.example (comment each with the dashboard URL from PLATFORM DETAILS)
- NEXT_PUBLIC_SITE_URL
- CONVEX_DEPLOYMENT
- NEXT_PUBLIC_CONVEX_URL
- STRIPE_SECRET_KEY
- STRIPE_WEBHOOK_SECRET
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.