Architecture
Next.js 16 App Router
Buildstory uses the Next.js 16 App Router with React 19 and TypeScript. The application follows a server-first architecture:- Server Components: All pages are server components by default, fetching data server-side
- Server Actions: All mutations use Next.js server actions with
"use server"directive - Client Components: Interactivity isolated to specific UI components
- Streaming: Progressive rendering with React Suspense boundaries
Database Stack
Serverless Postgres with branch-based isolation:
devbranch for local development and preview deploymentsmainbranch for production- HTTP adapter via
@neondatabase/serverless
Type-safe SQL query builder with:
- Schema-first design in
lib/db/schema.ts - Relational queries with
withAPI - Migration-based schema changes
- Full TypeScript inference
Tech Stack Summary
Core Framework
- Next.js 16 (App Router, React 19, TypeScript)
- Deployment: Vercel with automatic preview deployments
- Path Aliases:
@/maps to project root
Styling & UI
- Tailwind CSS v4 with custom configuration
- shadcn/ui (new-york style) for component primitives
- Radix UI for accessible headless components
- Motion (Framer Motion) for animations
- Fonts: DM Sans (body), Instrument Serif (headings), DM Mono (code)
Authentication & Authorization
Custom UI implementation (not pre-built components):
- Email/password and OAuth (Google, GitHub)
- Custom sign-in/sign-up forms in
app/(auth)/ - Just-in-time profile creation via
ensureProfile()
Three-tier role system:
user(default)moderator(can hide users, ban users)admin(full access, can manage roles)- Super-admin override via
ADMIN_USER_IDSenv var
Data Layer
Connection:
@neondatabase/serverless HTTP adapterClient in
lib/db/index.ts with full relational schemanpm run db:generate— generate migration from schema changesnpm run db:migrate— run pending migrations- Production migrations automated in CI on merge to
main
Integrations
Fire-and-forget webhooks in
lib/discord.ts:- Signup notifications
- Project creation notifications
- Milestone alerts (10, 25, 50, 75, 100+ signups/projects)
Embedded studio at
/studio (admin-only):- Sponsor logo management
- Volunteer role content
- Homepage content management
Configured for server, edge, and client runtimes:
- Server actions use
Sentry.captureExceptionwith tags - Component and action tags for debugging
- Extra context in error reports
Development Tools
- Unit tests in
__tests__/unit/(no DB required) - Integration tests in
__tests__/integration/(real Neon DB) - Mocked: Clerk auth, Sentry, Discord webhooks
- Pre-commit hooks via Husky + lint-staged
- Rules: no-console (warn), prefer-const, eqeqeq
Three workflows:
lint.yml— runs on PRstest.yml— unit + integration tests on PRsdeploy.yml— migrates production DB, then triggers Vercel deploy
Request Flow
Authentication Flow
- User signs in via Clerk custom form (
app/(auth)/sign-in) - Clerk middleware (
proxy.ts) validates session ensureProfile(clerkId)creates profile record just-in-time- Profile created with default
userrole - Subsequent requests use cached profile (React
cache())
Data Mutation Flow
- Client component calls server action
- Server action:
- Validates authentication via
auth() - Ensures profile exists with
ensureProfile() - Validates input with Zod schemas
- Performs database mutations
- Handles errors with Sentry
- Revalidates affected paths
- Validates authentication via
- Returns
ActionResult<T>type:
Error Handling Pattern
All server actions follow a consistent error handling pattern:Environment Variables
Required (Development & Production)
DATABASE_URL— Neon Postgres connection stringNEXT_PUBLIC_CLERK_PUBLISHABLE_KEY— Clerk publishable keyCLERK_SECRET_KEY— Clerk secret keyNEXT_PUBLIC_CLERK_SIGN_IN_URL—/sign-inNEXT_PUBLIC_CLERK_SIGN_UP_URL—/sign-upNEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL—/dashboardNEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL—/hackathonADMIN_USER_IDS— Comma-separated Clerk user IDs with super-admin access
Optional
DISCORD_WEBHOOK_SIGNUPS— Discord webhook for signup notificationsDISCORD_WEBHOOK_MILESTONES— Discord webhook for milestone alertsDISCORD_WEBHOOK_TEAM_CHAT— Discord webhook for team chat notificationsNEXT_PUBLIC_MAPBOX_TOKEN— Mapbox access token for Globe componentTWITCH_CLIENT_ID— Twitch API client ID for streamers featureTWITCH_CLIENT_SECRET— Twitch API client secretLINEAR_API_KEY— Linear API key for issue tracking integrationLINEAR_TEAM_ID— Linear team identifierLINEAR_PROJECT_ID— Linear project identifierLINEAR_LABEL_ID— Linear label identifier for categorizationSENTRY_AUTH_TOKEN— Sentry authentication token for releasesSENTRY_ORG— Sentry organization slugSENTRY_PROJECT— Sentry project slug
CI-Only
PRODUCTION_DATABASE_URL— Production Neon connection stringVERCEL_DEPLOY_HOOK— Vercel deploy hook URL
Next Steps
Database Schema
Complete reference for all tables, fields, and relationships
Server Actions
API reference for all server actions organized by feature area