Project Structure
The codebase at a glance — folders, conventions, and where to make what change.
Top-level layout
my-launch-site/
├── app/ # Next.js App Router (routes + server components)
│ ├── admin/ # /admin panel
│ ├── api/ # Route handlers (cron, upload, stripe, submissions, sponsor)
│ ├── batches/ # /batches/[year]/[week] archive
│ ├── blog/ # /blog + /blog/[slug]
│ ├── p/[slug]/ # Product detail pages
│ ├── submit/ # Submission form
│ ├── sponsor/ # Sponsor slot booking
│ ├── newsletter/ # Subscribe page
│ ├── profile/ # User's own submissions + votes
│ └── ... # Auth pages, legal pages, etc.
├── components/ # Shared React components (client + server)
├── config/ # Compile-time config (SITE_URL, SITE_NAME default, etc.)
├── emails/ # React Email templates
├── hooks/ # Client-side React hooks
├── lib/ # Business logic (server-only)
│ ├── actions/ # Server actions
│ ├── db/ # Drizzle schema + client + seed
│ └── *.ts # Domain modules
├── public/ # Static assets
├── scripts/ # CLI scripts (setup, seed, send-test-newsletter, simulate-crons)
├── docker-compose.yml # Local Postgres + Redis
├── drizzle.config.ts # Drizzle Kit config
├── next.config.mjs # Next config + image remotePatterns + CSP headers
└── proxy.ts # MiddlewareRouting conventions
Standard Next.js App Router:
page.tsx— route UI (default export)layout.tsx— wraps childrenloading.tsx— Suspense skeletonerror.tsx— error boundaryroute.ts— API handlers
Server components are default. Client components opt-in via "use client".
Where to change what
| You want to... | Edit... |
|---|---|
| Rebrand (name, fonts, description) | /admin/settings UI — or config/site.ts for compile-time defaults |
| Homepage layout | app/page.tsx |
| Submission flow | app/submit/ + app/api/submissions/route.ts |
| Admin moderation UI | app/admin/submissions/submission-list.tsx |
| Add a new setting | lib/settings-shared.ts |
| Product card design | components/product-card.tsx |
| Weekly cron | app/api/cron/weekly-batch/route.ts |
| DB schema | lib/db/schema.ts — then bun run db:push |
| Email template | emails/ + lib/emails.ts |
| Rate limit key | lib/rate-limit.ts |
Server vs client boundary
- Server-only: everything under
lib/(DB, Stripe, Redis, email, auth). Some modules import"server-only"at the top to enforce at build time. - Client components: live in
components/or alongside routes with"use client"at the top. Use for interactivity (vote button, filters, form UI). - Server actions: in
lib/actions/— the client calls a typed function, it runs on the server.
Never import lib/db, lib/stripe, or lib/plunk from a client component — TypeScript catches it.
Naming conventions
- React components:
PascalCase.tsx - Hooks:
use-hook-name.ts - Server actions:
camelCase.ts - Route folders:
kebab-case/
Scripts
Under scripts/:
| Script | What it does |
|---|---|
setup.ts | Full setup orchestrator (check deps, start DB, push schema, seed) |
seed-products.ts | Inserts a demo batch with 9 products |
send-test-newsletter.ts | Sends a test weekly newsletter via Plunk |
simulate-crons.ts | In-memory dry-run of cron logic (no DB mutations) |