AI-powered text-to-speech and voice tooling. The web app lets signed-in users explore voices, generate speech from text, and manage generations backed by PostgreSQL and object storage.
- Framework: Next.js (App Router), React 19, TypeScript
- Auth & orgs: Clerk (sign-in, organization context)
- API: tRPC with TanStack Query
- Database: PostgreSQL via Prisma (client generated to
src/generated/prisma) - Storage: Cloudflare R2 (S3-compatible) for audio assets
- TTS backend: Chatterbox API (
CHATTERBOX_API_URL,CHATTERBOX_API_KEY) - UI: Tailwind CSS, Radix UI / Base UI, shadcn-style components
- Observability: Sentry (
@sentry/nextjs)
- Node.js 20+ (matches
@types/nodein the repo) - pnpm (lockfile:
pnpm-lock.yaml) - A PostgreSQL database
- Clerk application (publishable + secret keys)
- R2 bucket and API credentials for uploads
- Access to the Chatterbox TTS API (URL + key)
-
Install dependencies
pnpm install
-
Configure environment
Create a
.envor.env.localfile in the project root. Server-side variables validated insrc/lib/env.tsare:Variable Purpose DATABASE_URLPostgreSQL connection string APP_URLCanonical app URL (used by the tRPC client and server) R2_ACCOUNT_IDCloudflare account ID R2_ACCESS_KEY_IDR2 S3 access key R2_SECRET_ACCESS_KEYR2 S3 secret R2_BUCKET_NAMEBucket name CHATTERBOX_API_URLBase URL of the Chatterbox API (used by the app and by pnpm sync-apias{url}/openapi.json)CHATTERBOX_API_KEYAPI key for Chatterbox Clerk expects its standard environment variables (for example
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEYandCLERK_SECRET_KEY). Configure those in the same env file.For tooling that must run without full secrets (for example Docker builds), you can set
SKIP_ENV_VALIDATION=1to skip strict env validation (seesrc/lib/env.ts). -
Database
Apply migrations and ensure the Prisma client is generated (also runs on
postinstall):pnpm exec prisma migrate dev -
Run the dev server
pnpm dev
Open http://localhost:3000. Unauthenticated users are redirected to Clerk sign-in; after sign-in, users without an active organization are sent to
/org-selection.
| Command | Description |
|---|---|
pnpm dev |
Start Next.js in development mode |
pnpm build |
Production build |
pnpm start |
Start production server |
pnpm lint |
Run ESLint |
pnpm sync-api |
Fetch Chatterbox OpenAPI from CHATTERBOX_API_URL/openapi.json and regenerate src/types/chatterbox-api.d.ts |
sync-api loads .env via dotenv (see scripts/sync-api.ts); set CHATTERBOX_API_URL before running.
Deploy as a Node web service on Railway (not Vercel):
- Create a project from this repository and add a PostgreSQL database. Railway provides
DATABASE_URL; reference it for Prisma. - Set environment variables on the app service for everything listed under Getting started → Configure environment, including Clerk keys, R2, Chatterbox, and
APP_URL. Use your Railway-generated HTTPS URL (or custom domain) forAPP_URL. - Build — example:
pnpm install --frozen-lockfile && pnpm exec prisma generate && pnpm build. Ensure Node 20+ (setNIXPACKS_NODE_VERSIONor Railway’s Node version setting if needed). - Start —
pnpm start(runsnext start). - Migrations — run
pnpm exec prisma migrate deployon each release (Railway Release Command, a one-off deploy task, or your CI) so production schema matchesprisma/migrations. - Clerk — in the Clerk dashboard, add the Railway URL (and production domain if any) to allowed origins, redirect URLs, and CORS as required.
src/app/— App Router routes, layouts, providerssrc/features/— Feature UI (dashboard, text-to-speech, voices, etc.)src/trpc/— tRPC routers and client setupprisma/— Schema and migrationsscripts/sync-api.ts— OpenAPI type generation for the TTS API
Private project ("private": true in package.json).