Auth and member portal for WDCC, built on Next.js 16 (App Router, Turbopack) with Better Auth, Drizzle ORM, and Neon Postgres.
- Next.js 16 — App Router, Turbopack build, React 19
- Better Auth — session + OAuth (Google), role-based access via
additionalFields - Drizzle ORM + Neon serverless Postgres
- TanStack Query — client-side data fetching
- Tailwind CSS v4
- pnpm — package manager (pinned via
packageManagerfield)
Install deps:
pnpm installCreate .env at the repo root:
DATABASE_URL=postgres://...
GOOGLE_CLIENT_ID=...
GOOGLE_CLIENT_SECRET=...
BETTER_AUTH_SECRET=...
BETTER_AUTH_URL=http://localhost:3000Apply schema to the database:
pnpm db:pushRun the dev server:
pnpm devOpen http://localhost:3000.
| Script | What it does |
|---|---|
pnpm dev |
Start dev server |
pnpm build |
Production build |
pnpm start |
Run production build |
pnpm lint |
ESLint |
pnpm typecheck |
tsc --noEmit |
pnpm format / format:check |
Prettier write / check |
pnpm db:generate |
Generate Drizzle migration from schema |
pnpm db:migrate |
Apply migrations |
pnpm db:push |
Push schema directly (dev) |
pnpm db:studio |
Open Drizzle Studio |
src/
app/ # App Router routes
api/auth/ # Better Auth handler
home/ # Authed user pages
admin/ # Admin-only pages
components/ # Shared React components
lib/
auth.ts # Better Auth server config
auth-client.ts # Better Auth React client
access.ts # requireUser / requireAdmin guards
db/ # Drizzle client, schema, migrations
Page protection uses the helpers in src/lib/access.ts — call requireUser() or requireAdmin() at the top of a server component to redirect unauthenticated or unauthorized users.
.github/workflows/ci.yaml runs on PRs:
pnpm format:checkpnpm typecheckpnpm build
Secrets (DATABASE_URL, GOOGLE_CLIENT_*, BETTER_AUTH_*) must be set in the repo's Actions secrets.
kyselyis pinned to0.28.17viapnpm.overridesinpackage.json.@better-auth/kysely-adapter@1.6.12importsDEFAULT_MIGRATION_TABLE, which was removed in kysely0.29. Remove the override once the upstream Better Auth fix is released.