Clubedge/clubedge-starter

Production-ready full-stack TypeScript starter for Next.js or TanStack Start: PostgreSQL with Drizzle, and optional modules for auth (Supabase, Better Auth), storage, cache, email, Stripe payments, background jobs (pg-boss), and observability (OpenTelemetry, Sentry). Local services with or without Docker, deploy configs, and full CI.

TypeScript

2

132 commits

updated Oct 12, 2026

See the code

See what people are saying

SourceMessageScoreDate

I built a CLI to scaffold Next.js monorepos with one command (r/opensource)

I've been building and maintaining multiple web projects, and I kept running into the same problem: every new project required repeating a lot of setup work before I could focus on building the actual product. So I built **create-clubedge-app**, a CLI that generates a Next.js monorepo from a…

3

Oct 9, 2026

README

Clubedge Starter

A production-ready full-stack TypeScript starter that ships only the modules you choose.

Next.js or TanStack Start on PostgreSQL, with optional auth, storage, email, payments,
background jobs, observability, and deployment, each behind an interface you can replace.

CI Generated projects Release npm License: Apache-2.0

Website · Create a project · Setup guide · Roadmap · Releases

pnpm dlx @clubedge/create-clubedge-app my-app

Why Clubedge Starter

Most starters give you one stack and leave you to rip out what you don't need. Removing a provider means hunting down its package, its environment variables, its docs, and its lockfile entries, and once you have changed the code, a newer version of the starter is something you can only copy from by hand.

Clubedge Starter is built the other way around. Every service is an optional module, and a module you leave out is removed completely. Each provider sits behind an interface in its own package, so you can swap Supabase Auth for Better Auth, or OpenTelemetry for Sentry, without touching your pages. And because create-clubedge-app records exactly what your project was generated from, it can add, remove, or upgrade modules later by merging the change into your code, keeping your edits.

Every combination in the CI matrix is generated as a real project and runs its full pipeline: install, lint, typecheck, unit tests, browser tests against real local services, a production build, and a smoke test.

Features

Application

  • Next.js App Router with React, TypeScript, Tailwind CSS 4, and shadcn/ui using Base UI primitives.
  • TanStack Start with React, TypeScript, Vite, Tailwind CSS 4, and shadcn/ui using Base UI primitives.
  • pnpm workspaces and Turborepo, with the web app in apps/web and framework-agnostic packages under packages/.
  • Drizzle ORM and PostgreSQL schema, migrations, and seed commands.
  • Zod environment validation, security headers, structured errors, and /api/health.
  • A landing page and a working dashboard built from the shared UI package.

Modules

  • Supabase Auth with server-verified sessions in secure cookies, a protected dashboard, and rate-limited sign-in.
  • Better Auth with users and sessions in your own PostgreSQL, secure session cookies, a protected dashboard, and rate-limited sign-in.
  • Password reset by email, and email verification that can be required before sign-in.
  • Password reset by email, sent by Supabase.
  • An account settings page: display name, password change, and account deletion.
  • Email over SMTP, for any provider or a local inbox; development prints emails to the server log until SMTP is configured.
  • Email through Resend; development prints emails to the server log until the API key is set.
  • S3-compatible storage adapter for AWS S3, Cloudflare R2, and MinIO.
  • Supabase Storage adapter that uses the signed-in user's session.
  • Fixed-window rate limiter and cache on Redis, falling back to process memory without REDIS_URL.
  • Fixed-window rate limiter and cache in process memory, suited to a single server instance.
  • Subscriptions with Stripe Checkout and the customer portal, kept in sync by verified webhooks, behind a provider-neutral payments interface.
  • Background jobs with retries and schedules, stored in PostgreSQL by pg-boss and run by a worker inside the app server, behind a provider-neutral jobs interface.
  • Server error reporting and request tracing with OpenTelemetry, to any OTLP collector, behind a provider-neutral observability interface.
  • Server error reporting and request tracing with Sentry, behind a provider-neutral observability interface.

Production

  • A production image that includes its own migrator (node /app/migrate.mjs), for running migrations before each release.
  • A manual deploy workflow for the chosen platform, and a readiness endpoint (/api/ready) that checks the database.
  • Deployment to Fly.io with fly.toml: migrations run as the release command.
  • Deployment to Railway with railway.json: migrations run before each deploy.
  • Deployment to Render with a render.yaml Blueprint: migrations run before each deploy.
  • Deployment to Vercel with apps/web/vercel.json: migrations run during the build.
  • Deployment to Netlify with apps/web/netlify.toml: migrations run during the build.

Quality

  • GitHub Actions CI with Vitest, Playwright, ESLint, and Prettier.
  • pnpm check:services, which proves the app can reach every configured service with a real round trip.

Modules

Pick modules when you create a project, and change them later with pnpm clubedge add and pnpm clubedge remove.

ModuleOptionsDefault
Frameworknext, tanstack-startnext
Authsupabase, better-auth, nonesupabase
Storages3, supabase, nones3
Cacheredis, memoryredis
Emailsmtp, resend, nonesmtp
Paymentsstripe, nonenone
Jobspg-boss, nonenone
Observabilityotel, sentry, nonenone
Local infradocker, supabase, local (no Docker), nonedocker
Deploydocker, fly, railway, render, vercel, netlifydocker

A module you leave out takes its packages, provider SDK, environment variables, documentation, and lockfile entries with it.

Quick start

To start a new application, create a project with the CLI as shown above; it contains only your modules. The steps below run this repository itself, with every module, for working on the Starter.

Requirements

  • Node.js 22.12 or newer (Node.js 22 LTS recommended).
  • pnpm 10.9.0. The repository pins its package manager version using Corepack.
  • PostgreSQL when using database features.

Install and run

corepack enable
pnpm install

Copy the example environment file to the web app's local environment file.

PowerShell:

Copy-Item .env.example apps/web/.env.local

macOS/Linux:

cp .env.example apps/web/.env.local

Start PostgreSQL and the other local services with Docker, apply the migrations, and check that the app can reach every service. The example environment already points at them.

pnpm infra:up
pnpm db:migrate
pnpm check:services

Start the local Supabase stack (it needs Docker), copy the publishable key that pnpm infra:status prints into apps/web/.env.local, and apply the migrations.

pnpm infra:up
pnpm infra:status
pnpm db:migrate
pnpm check:services

Nothing else to install: pnpm dev starts a local PostgreSQL database (PGlite, stored in .data/) next to the app and applies the migrations. Files go to a local folder until you configure object storage.

Set DATABASE_URL and your providers' settings in apps/web/.env.local, then run pnpm db:migrate and pnpm check:services.

Then start the app. SETUP.md describes every variable and provider.

pnpm dev

Open http://localhost:3000 for the landing page, http://localhost:3000/dashboard for the dashboard, or http://localhost:3000/api/health for the liveness endpoint. The pages render without connecting to providers; database and provider operations require their configuration.

[!NOTE] This is a foundation and a reference implementation. Review its security and deployment choices for your application before you go to production; SETUP.md has a checklist.

How it works

flowchart TB
  %% clubedge:if framework=next
  Browser --> App[Next.js application]
  %% clubedge:end
  %% clubedge:if framework=tanstack-start
  Browser --> App[TanStack Start application]
  %% clubedge:end
  App -->|Drizzle ORM| DB[(PostgreSQL)]
  %% clubedge:if auth=supabase
  App -->|auth interface and server sessions| Auth[Supabase Auth]
  %% clubedge:end
  %% clubedge:if auth=better-auth
  App -->|auth interface and server sessions| Auth[Better Auth]
  Auth -->|users and sessions| DB
  %% clubedge:end
  %% clubedge:if cache=redis
  App -->|cache and rate limits| Redis[(Redis, or memory)]
  %% clubedge:end
  %% clubedge:if email=smtp
  App -->|email interface| SMTP[SMTP server, or the log]
  %% clubedge:end
  %% clubedge:if email=resend
  App -->|email interface| Resend[Resend, or the log]
  %% clubedge:end
  %% clubedge:if storage=s3
  App -->|storage interface| S3[S3-compatible storage: AWS S3, R2, MinIO]
  %% clubedge:end
  %% clubedge:if storage=supabase
  App -->|storage interface| SupabaseStorage[Supabase Storage]
  %% clubedge:end
  %% clubedge:if payments=stripe
  App -->|payments interface| Stripe[Stripe Checkout and portal]
  Stripe -->|verified webhooks| App
  %% clubedge:end
  %% clubedge:if jobs=pg-boss
  App -->|jobs interface, worker in the server| Jobs[pg-boss]
  Jobs -->|jobs table| DB
  %% clubedge:end
  %% clubedge:if observability=otel
  App -->|traces and errors| Otel[OTLP collector]
  %% clubedge:end
  %% clubedge:if observability=sentry
  App -->|traces and errors| Sentry[Sentry]
  %% clubedge:end
  • PostgreSQL is the source of truth for application data. Drizzle centralizes application schema, queries, and migrations.
  • Authentication stays separate from application data. The auth provider owns credentials and sessions; application tables are managed by Drizzle.
  • Providers sit behind interfaces. Each interface lives in its own package under packages/, and each provider in another, so replacing a provider does not touch application code.
  • Shared packages are framework-agnostic. Packages under packages/ receive configuration and request cookies as arguments and never import a web framework. ESLint enforces these boundaries.
  • One composition root. apps/web/src/server/ is the only place that reads environment variables and chooses providers. Routes and components call it rather than a provider SDK.
  • Keep the baseline focused. Additional providers and tooling should be added when a real use case calls for them.

Common commands

Run these from the repository root:

CommandPurpose
pnpm devStart the web app in development mode.
pnpm buildCreate a production build.
pnpm startStart the production build.
pnpm lintRun ESLint.
pnpm typecheckTypecheck the workspaces.
pnpm testRun Vitest.
pnpm test:e2eRun Playwright browser checks.
pnpm formatFormat supported repository files.
pnpm format:checkCheck formatting without writing files.
pnpm db:generateGenerate Drizzle migrations from the schemas.
pnpm db:migrateApply checked-in Drizzle migrations.
pnpm db:pushPush schema directly (local development only).
pnpm db:studioOpen Drizzle Studio.
pnpm db:checkCheck migration consistency.
pnpm db:seedSeed the configured database.

Playwright's first run may require installing Chromium with pnpm exec playwright install chromium. CI runs the browser checks automatically.

Local services:

  • pnpm check:services: check every configured service with a real round trip.
  • pnpm infra:up and pnpm infra:down: start and stop the local services from docker-compose.dev.yml.
  • pnpm infra:reset: stop them and delete their data. pnpm infra:logs follows their logs.
  • pnpm infra:up and pnpm infra:down: start and stop the local Supabase stack.
  • pnpm infra:status: print its URLs and keys. pnpm infra:reset stops it and deletes its data.
  • pnpm infra:up: run only the local database, for example for pnpm check:services or browser tests.
  • pnpm infra:reset: delete the local database and files in .data/ (stop pnpm dev first).

Check the project:

  • pnpm clubedge status: the project's Starter release, modules, and Git state, whether a newer Starter release exists, and the command to run next.
  • pnpm clubedge doctor: check Node.js, pnpm, the dependencies, the lockfile, and apps/web/.env.local against the example, then run pnpm check:services. It changes nothing and exits with an error when a check fails.

Change the project later:

  • pnpm clubedge add <module> <option>: add a module or switch its option, for example pnpm clubedge add auth better-auth or pnpm clubedge add infra local. Name several to change them together, as in pnpm clubedge add email resend payments stripe. Run pnpm clubedge add without arguments to choose from a list.
  • pnpm clubedge remove <module>: remove one or more modules, for example pnpm clubedge remove storage.
  • pnpm clubedge upgrade: move the project to the newest Starter release. It first lists the releases in between.

These commands merge the change into your code instead of overwriting it: files you never touched are updated, your edits are kept, and lines you both changed get conflict markers, listed per file afterward. Commit first, because they need a clean Git tree so that git diff shows the result. Add --dry-run to preview a change.

Documentation

I want toRead
Configure the environment and each providerSETUP.md
Run the local servicesLocal services
Deploy the appDeploy
Check the app before going liveBefore deploying
Fix a common problemTroubleshooting
Contribute codeCONTRIBUTING.md
Get helpSUPPORT.md
Report a security problemSECURITY.md

Working on this repository

This repository contains the same application for two frameworks, Next.js (apps/web) and TanStack Start (apps/start), plus every optional module. Sections of this README marked for a framework or module appear only in projects that use it.

The TanStack Start app is apps/start, run with pnpm --filter @clubedge/start dev. It reads apps/start/.env.local, copied from apps/start/.env.example. Run the browser suite against it with E2E_APP=start pnpm test:e2e, and build its image with docker build -f apps/start/Dockerfile --build-arg APP_DIR=apps/start --build-arg APP_PACKAGE=@clubedge/start ..

clubedge.template.json tells create-clubedge-app what each framework and module owns: packages, files, variant files under variants/ that replace a default, and files with clubedge:if blocks. Write those blocks so the default selection keeps every block; use a variant file when two options need different code. .github/workflows/starter.yml generates projects for several combinations and runs their full pipeline. Maintainers can use PUBLISHING.md for the GitHub launch checklist.

Repository structure

  • apps/web/: the web app, with routes, UI, and the composition root in src/server/
  • e2e/: Playwright browser checks
  • packages/core/: errors, Result type, HTTP helpers, and the error reporting and tracing hooks (no dependencies)
  • packages/db/: Drizzle schema, client factory, migrations, and seed script
  • packages/auth/: AuthProvider and CookieStore interfaces
  • packages/auth-supabase/: Supabase Auth adapter
  • packages/auth-better-auth/: Better Auth adapter, with its own tables and migrations
  • packages/storage/: StorageProvider interface
  • packages/storage-s3/: S3-compatible storage adapter
  • packages/storage-supabase/: Supabase Storage adapter
  • packages/cache/: Cache and RateLimiter interfaces with in-memory implementations
  • packages/cache-redis/: Redis rate limiter and cache
  • packages/email/: EmailProvider interface with console and in-memory providers
  • packages/email-smtp/: SMTP email provider
  • packages/email-resend/: Resend email provider
  • packages/payments/: PaymentProvider interface, billing logic, and the subscription tables
  • packages/payments-stripe/: Stripe payment provider
  • packages/jobs/: JobQueue interface, job definitions, and an in-memory queue for tests
  • packages/jobs-pg-boss/: pg-boss job queue
  • packages/observability/: ObservabilityProvider interface and an in-memory provider for tests
  • packages/observability-otel/: OpenTelemetry provider (OTLP/HTTP traces and error logs)
  • packages/observability-sentry/: Sentry provider
  • packages/ui/: shared shadcn/ui components, utilities, and global theme styles
  • .github/: CI workflow, issue forms, and pull request template
  • SETUP.md, CONTRIBUTING.md, SECURITY.md: setup, contribution, and security guides

The project name, description, service identifier, and documentation links live in apps/web/src/config/site.json. Edit that file to rename the app; create-clubedge-app writes it for generated projects.

Shared UI components

The shared component package is @clubedge/ui. It uses the shadcn base-nova style, which generates components backed by @base-ui/react rather than Radix UI. The landing page and dashboard demonstrate the shared sidebar, breadcrumbs, theme switch, buttons, cards, badges, separators, inputs, labels, and tables. The light/dark theme preference is stored in the browser; dark mode uses a #151515 page background and blue #2563eb primary color.

Add a component from the repository root using the web app's config:

pnpm dlx shadcn@latest add badge -c apps/web

Shared components are generated under packages/ui/src/components and can be imported from @clubedge/ui/components/<component>. The app and packages/ui components.json files intentionally share the base-nova style, neutral color base, Lucide icons, Tailwind v4 stylesheet, and RTL-aware generation setting. The app currently renders English in LTR; set the root document's lang and dir for the locale used by your application. Put app-only components in apps/web/src/components.

Roadmap

Each phase ends with a Starter release and a create-clubedge-app release pinned to it. The full plan is in ROADMAP.md.

ReleaseTheme
v0.5.0 to v0.8.0Optional modules, local services with and without Docker, add, remove, and upgrade
v0.9.0Email, password reset, and email verification
v0.10.0Deployment to Docker hosts, Fly.io, Railway, Render, Vercel, and Netlify
v0.11.0Payments with Stripe
v0.12.0Background jobs with pg-boss
v0.13.0Observability with OpenTelemetry or Sentry
nextBrowser error reporting, Sentry source maps, and auth emails through the job queue

Community

Everyone taking part is expected to follow the code of conduct.

Contributing

Please read CONTRIBUTING.md before opening an issue or pull request. For local changes, run the relevant checks before submitting. You can report vulnerabilities privately using the process in SECURITY.md.

License

Copyright © 2026 Clubedge Digital Systems. This project is licensed under the Apache License, Version 2.0. See LICENSE and NOTICE.

better-auth
ci-cd
docker
drizzle-orm
monorepo
nextjs
opentelemetry
pg-boss
playwright
pnpm
postgresql
redis
sentry
stripe
supabase
tailwindcss
tanstack-start
turborepo
typescript
vitest

Clubedge/clubedge-starter

Production-ready full-stack TypeScript starter for Next.js or TanStack Start: PostgreSQL with Drizzle, and optional modules for auth (Supabase, Better Auth), storage, cache, email, Stripe payments, background jobs (pg-boss), and observability (OpenTelemetry, Sentry). Local services with or without Docker, deploy configs, and full CI.

TypeScript

2

132 commits

updated Oct 12, 2026

See the code

See what people are saying

SourceMessageScoreDate

I built a CLI to scaffold Next.js monorepos with one command (r/opensource)

I've been building and maintaining multiple web projects, and I kept running into the same problem: every new project required repeating a lot of setup work before I could focus on building the actual product. So I built **create-clubedge-app**, a CLI that generates a Next.js monorepo from a…

3

Oct 9, 2026

README

Clubedge Starter

A production-ready full-stack TypeScript starter that ships only the modules you choose.

Next.js or TanStack Start on PostgreSQL, with optional auth, storage, email, payments,
background jobs, observability, and deployment, each behind an interface you can replace.

CI Generated projects Release npm License: Apache-2.0

Website · Create a project · Setup guide · Roadmap · Releases

pnpm dlx @clubedge/create-clubedge-app my-app

Why Clubedge Starter

Most starters give you one stack and leave you to rip out what you don't need. Removing a provider means hunting down its package, its environment variables, its docs, and its lockfile entries, and once you have changed the code, a newer version of the starter is something you can only copy from by hand.

Clubedge Starter is built the other way around. Every service is an optional module, and a module you leave out is removed completely. Each provider sits behind an interface in its own package, so you can swap Supabase Auth for Better Auth, or OpenTelemetry for Sentry, without touching your pages. And because create-clubedge-app records exactly what your project was generated from, it can add, remove, or upgrade modules later by merging the change into your code, keeping your edits.

Every combination in the CI matrix is generated as a real project and runs its full pipeline: install, lint, typecheck, unit tests, browser tests against real local services, a production build, and a smoke test.

Features

Application

  • Next.js App Router with React, TypeScript, Tailwind CSS 4, and shadcn/ui using Base UI primitives.
  • TanStack Start with React, TypeScript, Vite, Tailwind CSS 4, and shadcn/ui using Base UI primitives.
  • pnpm workspaces and Turborepo, with the web app in apps/web and framework-agnostic packages under packages/.
  • Drizzle ORM and PostgreSQL schema, migrations, and seed commands.
  • Zod environment validation, security headers, structured errors, and /api/health.
  • A landing page and a working dashboard built from the shared UI package.

Modules

  • Supabase Auth with server-verified sessions in secure cookies, a protected dashboard, and rate-limited sign-in.
  • Better Auth with users and sessions in your own PostgreSQL, secure session cookies, a protected dashboard, and rate-limited sign-in.
  • Password reset by email, and email verification that can be required before sign-in.
  • Password reset by email, sent by Supabase.
  • An account settings page: display name, password change, and account deletion.
  • Email over SMTP, for any provider or a local inbox; development prints emails to the server log until SMTP is configured.
  • Email through Resend; development prints emails to the server log until the API key is set.
  • S3-compatible storage adapter for AWS S3, Cloudflare R2, and MinIO.
  • Supabase Storage adapter that uses the signed-in user's session.
  • Fixed-window rate limiter and cache on Redis, falling back to process memory without REDIS_URL.
  • Fixed-window rate limiter and cache in process memory, suited to a single server instance.
  • Subscriptions with Stripe Checkout and the customer portal, kept in sync by verified webhooks, behind a provider-neutral payments interface.
  • Background jobs with retries and schedules, stored in PostgreSQL by pg-boss and run by a worker inside the app server, behind a provider-neutral jobs interface.
  • Server error reporting and request tracing with OpenTelemetry, to any OTLP collector, behind a provider-neutral observability interface.
  • Server error reporting and request tracing with Sentry, behind a provider-neutral observability interface.

Production

  • A production image that includes its own migrator (node /app/migrate.mjs), for running migrations before each release.
  • A manual deploy workflow for the chosen platform, and a readiness endpoint (/api/ready) that checks the database.
  • Deployment to Fly.io with fly.toml: migrations run as the release command.
  • Deployment to Railway with railway.json: migrations run before each deploy.
  • Deployment to Render with a render.yaml Blueprint: migrations run before each deploy.
  • Deployment to Vercel with apps/web/vercel.json: migrations run during the build.
  • Deployment to Netlify with apps/web/netlify.toml: migrations run during the build.

Quality

  • GitHub Actions CI with Vitest, Playwright, ESLint, and Prettier.
  • pnpm check:services, which proves the app can reach every configured service with a real round trip.

Modules

Pick modules when you create a project, and change them later with pnpm clubedge add and pnpm clubedge remove.

ModuleOptionsDefault
Frameworknext, tanstack-startnext
Authsupabase, better-auth, nonesupabase
Storages3, supabase, nones3
Cacheredis, memoryredis
Emailsmtp, resend, nonesmtp
Paymentsstripe, nonenone
Jobspg-boss, nonenone
Observabilityotel, sentry, nonenone
Local infradocker, supabase, local (no Docker), nonedocker
Deploydocker, fly, railway, render, vercel, netlifydocker

A module you leave out takes its packages, provider SDK, environment variables, documentation, and lockfile entries with it.

Quick start

To start a new application, create a project with the CLI as shown above; it contains only your modules. The steps below run this repository itself, with every module, for working on the Starter.

Requirements

  • Node.js 22.12 or newer (Node.js 22 LTS recommended).
  • pnpm 10.9.0. The repository pins its package manager version using Corepack.
  • PostgreSQL when using database features.

Install and run

corepack enable
pnpm install

Copy the example environment file to the web app's local environment file.

PowerShell:

Copy-Item .env.example apps/web/.env.local

macOS/Linux:

cp .env.example apps/web/.env.local

Start PostgreSQL and the other local services with Docker, apply the migrations, and check that the app can reach every service. The example environment already points at them.

pnpm infra:up
pnpm db:migrate
pnpm check:services

Start the local Supabase stack (it needs Docker), copy the publishable key that pnpm infra:status prints into apps/web/.env.local, and apply the migrations.

pnpm infra:up
pnpm infra:status
pnpm db:migrate
pnpm check:services

Nothing else to install: pnpm dev starts a local PostgreSQL database (PGlite, stored in .data/) next to the app and applies the migrations. Files go to a local folder until you configure object storage.

Set DATABASE_URL and your providers' settings in apps/web/.env.local, then run pnpm db:migrate and pnpm check:services.

Then start the app. SETUP.md describes every variable and provider.

pnpm dev

Open http://localhost:3000 for the landing page, http://localhost:3000/dashboard for the dashboard, or http://localhost:3000/api/health for the liveness endpoint. The pages render without connecting to providers; database and provider operations require their configuration.

[!NOTE] This is a foundation and a reference implementation. Review its security and deployment choices for your application before you go to production; SETUP.md has a checklist.

How it works

flowchart TB
  %% clubedge:if framework=next
  Browser --> App[Next.js application]
  %% clubedge:end
  %% clubedge:if framework=tanstack-start
  Browser --> App[TanStack Start application]
  %% clubedge:end
  App -->|Drizzle ORM| DB[(PostgreSQL)]
  %% clubedge:if auth=supabase
  App -->|auth interface and server sessions| Auth[Supabase Auth]
  %% clubedge:end
  %% clubedge:if auth=better-auth
  App -->|auth interface and server sessions| Auth[Better Auth]
  Auth -->|users and sessions| DB
  %% clubedge:end
  %% clubedge:if cache=redis
  App -->|cache and rate limits| Redis[(Redis, or memory)]
  %% clubedge:end
  %% clubedge:if email=smtp
  App -->|email interface| SMTP[SMTP server, or the log]
  %% clubedge:end
  %% clubedge:if email=resend
  App -->|email interface| Resend[Resend, or the log]
  %% clubedge:end
  %% clubedge:if storage=s3
  App -->|storage interface| S3[S3-compatible storage: AWS S3, R2, MinIO]
  %% clubedge:end
  %% clubedge:if storage=supabase
  App -->|storage interface| SupabaseStorage[Supabase Storage]
  %% clubedge:end
  %% clubedge:if payments=stripe
  App -->|payments interface| Stripe[Stripe Checkout and portal]
  Stripe -->|verified webhooks| App
  %% clubedge:end
  %% clubedge:if jobs=pg-boss
  App -->|jobs interface, worker in the server| Jobs[pg-boss]
  Jobs -->|jobs table| DB
  %% clubedge:end
  %% clubedge:if observability=otel
  App -->|traces and errors| Otel[OTLP collector]
  %% clubedge:end
  %% clubedge:if observability=sentry
  App -->|traces and errors| Sentry[Sentry]
  %% clubedge:end
  • PostgreSQL is the source of truth for application data. Drizzle centralizes application schema, queries, and migrations.
  • Authentication stays separate from application data. The auth provider owns credentials and sessions; application tables are managed by Drizzle.
  • Providers sit behind interfaces. Each interface lives in its own package under packages/, and each provider in another, so replacing a provider does not touch application code.
  • Shared packages are framework-agnostic. Packages under packages/ receive configuration and request cookies as arguments and never import a web framework. ESLint enforces these boundaries.
  • One composition root. apps/web/src/server/ is the only place that reads environment variables and chooses providers. Routes and components call it rather than a provider SDK.
  • Keep the baseline focused. Additional providers and tooling should be added when a real use case calls for them.

Common commands

Run these from the repository root:

CommandPurpose
pnpm devStart the web app in development mode.
pnpm buildCreate a production build.
pnpm startStart the production build.
pnpm lintRun ESLint.
pnpm typecheckTypecheck the workspaces.
pnpm testRun Vitest.
pnpm test:e2eRun Playwright browser checks.
pnpm formatFormat supported repository files.
pnpm format:checkCheck formatting without writing files.
pnpm db:generateGenerate Drizzle migrations from the schemas.
pnpm db:migrateApply checked-in Drizzle migrations.
pnpm db:pushPush schema directly (local development only).
pnpm db:studioOpen Drizzle Studio.
pnpm db:checkCheck migration consistency.
pnpm db:seedSeed the configured database.

Playwright's first run may require installing Chromium with pnpm exec playwright install chromium. CI runs the browser checks automatically.

Local services:

  • pnpm check:services: check every configured service with a real round trip.
  • pnpm infra:up and pnpm infra:down: start and stop the local services from docker-compose.dev.yml.
  • pnpm infra:reset: stop them and delete their data. pnpm infra:logs follows their logs.
  • pnpm infra:up and pnpm infra:down: start and stop the local Supabase stack.
  • pnpm infra:status: print its URLs and keys. pnpm infra:reset stops it and deletes its data.
  • pnpm infra:up: run only the local database, for example for pnpm check:services or browser tests.
  • pnpm infra:reset: delete the local database and files in .data/ (stop pnpm dev first).

Check the project:

  • pnpm clubedge status: the project's Starter release, modules, and Git state, whether a newer Starter release exists, and the command to run next.
  • pnpm clubedge doctor: check Node.js, pnpm, the dependencies, the lockfile, and apps/web/.env.local against the example, then run pnpm check:services. It changes nothing and exits with an error when a check fails.

Change the project later:

  • pnpm clubedge add <module> <option>: add a module or switch its option, for example pnpm clubedge add auth better-auth or pnpm clubedge add infra local. Name several to change them together, as in pnpm clubedge add email resend payments stripe. Run pnpm clubedge add without arguments to choose from a list.
  • pnpm clubedge remove <module>: remove one or more modules, for example pnpm clubedge remove storage.
  • pnpm clubedge upgrade: move the project to the newest Starter release. It first lists the releases in between.

These commands merge the change into your code instead of overwriting it: files you never touched are updated, your edits are kept, and lines you both changed get conflict markers, listed per file afterward. Commit first, because they need a clean Git tree so that git diff shows the result. Add --dry-run to preview a change.

Documentation

I want toRead
Configure the environment and each providerSETUP.md
Run the local servicesLocal services
Deploy the appDeploy
Check the app before going liveBefore deploying
Fix a common problemTroubleshooting
Contribute codeCONTRIBUTING.md
Get helpSUPPORT.md
Report a security problemSECURITY.md

Working on this repository

This repository contains the same application for two frameworks, Next.js (apps/web) and TanStack Start (apps/start), plus every optional module. Sections of this README marked for a framework or module appear only in projects that use it.

The TanStack Start app is apps/start, run with pnpm --filter @clubedge/start dev. It reads apps/start/.env.local, copied from apps/start/.env.example. Run the browser suite against it with E2E_APP=start pnpm test:e2e, and build its image with docker build -f apps/start/Dockerfile --build-arg APP_DIR=apps/start --build-arg APP_PACKAGE=@clubedge/start ..

clubedge.template.json tells create-clubedge-app what each framework and module owns: packages, files, variant files under variants/ that replace a default, and files with clubedge:if blocks. Write those blocks so the default selection keeps every block; use a variant file when two options need different code. .github/workflows/starter.yml generates projects for several combinations and runs their full pipeline. Maintainers can use PUBLISHING.md for the GitHub launch checklist.

Repository structure

  • apps/web/: the web app, with routes, UI, and the composition root in src/server/
  • e2e/: Playwright browser checks
  • packages/core/: errors, Result type, HTTP helpers, and the error reporting and tracing hooks (no dependencies)
  • packages/db/: Drizzle schema, client factory, migrations, and seed script
  • packages/auth/: AuthProvider and CookieStore interfaces
  • packages/auth-supabase/: Supabase Auth adapter
  • packages/auth-better-auth/: Better Auth adapter, with its own tables and migrations
  • packages/storage/: StorageProvider interface
  • packages/storage-s3/: S3-compatible storage adapter
  • packages/storage-supabase/: Supabase Storage adapter
  • packages/cache/: Cache and RateLimiter interfaces with in-memory implementations
  • packages/cache-redis/: Redis rate limiter and cache
  • packages/email/: EmailProvider interface with console and in-memory providers
  • packages/email-smtp/: SMTP email provider
  • packages/email-resend/: Resend email provider
  • packages/payments/: PaymentProvider interface, billing logic, and the subscription tables
  • packages/payments-stripe/: Stripe payment provider
  • packages/jobs/: JobQueue interface, job definitions, and an in-memory queue for tests
  • packages/jobs-pg-boss/: pg-boss job queue
  • packages/observability/: ObservabilityProvider interface and an in-memory provider for tests
  • packages/observability-otel/: OpenTelemetry provider (OTLP/HTTP traces and error logs)
  • packages/observability-sentry/: Sentry provider
  • packages/ui/: shared shadcn/ui components, utilities, and global theme styles
  • .github/: CI workflow, issue forms, and pull request template
  • SETUP.md, CONTRIBUTING.md, SECURITY.md: setup, contribution, and security guides

The project name, description, service identifier, and documentation links live in apps/web/src/config/site.json. Edit that file to rename the app; create-clubedge-app writes it for generated projects.

Shared UI components

The shared component package is @clubedge/ui. It uses the shadcn base-nova style, which generates components backed by @base-ui/react rather than Radix UI. The landing page and dashboard demonstrate the shared sidebar, breadcrumbs, theme switch, buttons, cards, badges, separators, inputs, labels, and tables. The light/dark theme preference is stored in the browser; dark mode uses a #151515 page background and blue #2563eb primary color.

Add a component from the repository root using the web app's config:

pnpm dlx shadcn@latest add badge -c apps/web

Shared components are generated under packages/ui/src/components and can be imported from @clubedge/ui/components/<component>. The app and packages/ui components.json files intentionally share the base-nova style, neutral color base, Lucide icons, Tailwind v4 stylesheet, and RTL-aware generation setting. The app currently renders English in LTR; set the root document's lang and dir for the locale used by your application. Put app-only components in apps/web/src/components.

Roadmap

Each phase ends with a Starter release and a create-clubedge-app release pinned to it. The full plan is in ROADMAP.md.

ReleaseTheme
v0.5.0 to v0.8.0Optional modules, local services with and without Docker, add, remove, and upgrade
v0.9.0Email, password reset, and email verification
v0.10.0Deployment to Docker hosts, Fly.io, Railway, Render, Vercel, and Netlify
v0.11.0Payments with Stripe
v0.12.0Background jobs with pg-boss
v0.13.0Observability with OpenTelemetry or Sentry
nextBrowser error reporting, Sentry source maps, and auth emails through the job queue

Community

Everyone taking part is expected to follow the code of conduct.

Contributing

Please read CONTRIBUTING.md before opening an issue or pull request. For local changes, run the relevant checks before submitting. You can report vulnerabilities privately using the process in SECURITY.md.

License

Copyright © 2026 Clubedge Digital Systems. This project is licensed under the Apache License, Version 2.0. See LICENSE and NOTICE.

better-auth
ci-cd
docker
drizzle-orm
monorepo
nextjs
opentelemetry
pg-boss
playwright
pnpm
postgresql
redis
sentry
stripe
supabase
tailwindcss
tanstack-start
turborepo
typescript
vitest