create-saas-app-ai-chat
Version:
Create a production-ready AI SaaS with Next.js, Supabase, Stripe, and OpenRouter - 15+ AI models included
594 lines (437 loc) • 18.8 kB
Markdown
# AI SaaS Template
A production-ready AI SaaS starter template providing unified access to 15+ AI models (Claude, Gemini, Llama, DeepSeek, and more) through OpenRouter. Built with Next.js 15 with authentication, subscriptions, credits, and a complete dashboard - ready to customize for your AI product.
## Key Features
### AI Chat & Model Access
- **Multi-Model Support**: Access 15+ AI models through a single unified interface via OpenRouter
- **Intelligent Context Management**: Automatic conversation summarization when approaching token limits
- **Streaming Responses**: Real-time AI responses with server-sent events
- **Model Switching**: Change AI models mid-conversation without losing context
- **Token Tracking**: Detailed input/output token counts and cost breakdowns
### User Features
- **Conversation Management**: Organize chats, rename conversations, and delete old threads
- **Artifact System**: Customizable split-view display for AI-generated content (50/50 on desktop, overlay on mobile)
- **Usage Analytics**: Track token consumption and costs with interactive charts
- **Responsive Design**: Desktop and mobile-optimized interface
### Subscription & Billing
- **Trial Period**: 7-day trial for monthly plans, 14-day trial for yearly plans with $1 credit
- **Early Upgrade**: Convert from trial to paid subscription instantly without waiting for trial to end
- **Flexible Plans**: Multiple subscription tiers with different credit allocations
- **Stripe Integration**: Secure payment processing with customer portal for subscription management
- **Credit System**: USD-based credits (6 decimal precision) deducted based on actual API costs
- **Automatic Reset**: Monthly credit reset on subscription anniversary, yearly via cron job
### Developer Experience
- **Setup Wizard**: Interactive setup flow for environment configuration (development mode)
- **Type Safety**: Full TypeScript coverage with Drizzle ORM type inference
- **Modern Stack**: Next.js 15 App Router, React 19, Turbopack dev mode
- **Database Migrations**: Version-controlled schema changes with Drizzle migrations
- **Activity Logging**: Comprehensive audit trail for user actions
## Tech Stack
### Frontend
- **Next.js 15** - React framework with App Router and Server Components
- **React 19** - UI library with concurrent features
- **TypeScript 5** - Static type checking
- **Tailwind CSS 4** - Utility-first CSS framework
- **shadcn/ui** - Customizable UI components built on Radix UI
- **magicui** - Advanced animated components for marketing
- **Recharts** - Interactive usage analytics charts
- **Three.js** - 3D WebGL plasma background effect
### Backend
- **Next.js API Routes** - Serverless API endpoints
- **Server Actions** - Type-safe server-side mutations
- **OpenRouter** - Multi-model AI API aggregator
- **Stripe** - Payment processing and subscription management
- **Resend** - Transactional email service
### Database & Authentication
- **Supabase** - PostgreSQL database and authentication
- **Drizzle ORM** - Type-safe database queries and migrations
- **Neon** - Serverless PostgreSQL (via Supabase)
### Development Tools
- **Turbopack** - Fast development bundler
- **ESLint** - Code linting
- **Prettier** - Code formatting (via ESLint integration)
- **pnpm** - Fast, disk-space efficient package manager
## Getting Started
### Prerequisites
- **Node.js** 18.17 or later
- **pnpm** 8.0 or later (`npm install -g pnpm`)
- **Supabase Account** - [supabase.com](https://supabase.com)
- **Stripe Account** - [stripe.com](https://stripe.com)
- **OpenRouter API Key** - [openrouter.ai](https://openrouter.ai)
- **Resend API Key** - [resend.com](https://resend.com) (optional, for contact form)
### Installation
1. **Create a new project**
```bash
npx create-saas-app-ai-chat my-saas-app
cd my-saas-app
```
2. **Set up environment variables**
Create a `.env.local` file in the root directory:
```bash
cp .env.example .env.local
```
4. **Configure environment variables** (see [Environment Setup](#environment-setup) below)
5. **Run the setup wizard** (development mode only)
```bash
pnpm dev
```
Navigate to `http://localhost:3000` and follow the interactive setup flow.
### Environment Setup
Required environment variables in `.env.local`:
```env
# Supabase (Database & Authentication)
NEXT_PUBLIC_SUPABASE_URL=your_supabase_project_url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key
SUPABASE_SERVICE_ROLE_KEY=your_supabase_service_role_key
DATABASE_URL=your_supabase_database_connection_string
# Stripe (Payments & Subscriptions)
STRIPE_SECRET_KEY=your_stripe_secret_key
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=your_stripe_publishable_key
STRIPE_WEBHOOK_SECRET=your_stripe_webhook_secret
# OpenRouter (AI Models)
OPENROUTER_API_KEY=your_openrouter_api_key
AI_TEMPERATURE=0.7
# Email (Contact Form - Optional)
RESEND_API_KEY=your_resend_api_key
RESEND_FROM_EMAIL=noreply@yourdomain.com
RESEND_TO_EMAIL=contact@yourdomain.com
# App Configuration
NEXT_PUBLIC_BASE_URL=http://localhost:3000
SETUP_COMPLETE=false
# Cron Jobs (Production)
CRON_SECRET=your_random_secret_string
```
### Database Setup
#### Option 1: Using Setup Wizard (Recommended for Development)
1. Set `SETUP_COMPLETE=false` in `.env.local`
2. Run `pnpm dev`
3. Navigate to `http://localhost:3000`
4. Follow the setup wizard through all 5 steps
5. The wizard will automatically push the database schema
#### Option 2: Manual Setup
1. **Generate migration files** (after schema changes)
```bash
pnpm db:generate
```
2. **Apply migrations**
```bash
pnpm db:migrate
```
3. **Quick push** (development only, skips migrations)
```bash
pnpm db:push
```
4. **Open Drizzle Studio** (database GUI)
```bash
pnpm db:studio
```
### Stripe Configuration
#### 1. Create Products & Prices
In your Stripe Dashboard, create subscription products with the following metadata:
**Product Metadata:**
- `ai_credits_amount`: Amount in USD (e.g., "10.00" for $10)
**Example Products:**
- **Basic Plan (Monthly)**: $9/month, `ai_credits_amount: "10.00"`
- **Pro Plan (Monthly)**: $29/month, `ai_credits_amount: "35.00"`
- **Basic Plan (Yearly)**: $90/year, `ai_credits_amount: "120.00"`
- **Pro Plan (Yearly)**: $290/year, `ai_credits_amount: "420.00"`
#### 2. Configure Webhook
1. Go to **Developers > Webhooks** in Stripe Dashboard
2. Add endpoint: `https://yourdomain.com/api/stripe/webhook`
3. Select events to listen to:
- `checkout.session.completed`
- `customer.subscription.created`
- `customer.subscription.updated`
- `customer.subscription.deleted`
4. Copy the webhook signing secret to `STRIPE_WEBHOOK_SECRET` in `.env.local`
#### 3. Test Webhook Locally
```bash
# Install Stripe CLI
brew install stripe/stripe-cli/stripe
# Login to Stripe
stripe login
# Forward webhooks to local server
stripe listen --forward-to localhost:3000/api/stripe/webhook
```
## Development Workflow
### Available Scripts
```bash
# Development
pnpm dev # Start dev server with Turbopack (http://localhost:3000)
# Build & Production
pnpm build # Create production build
pnpm start # Start production server
# Code Quality
pnpm lint # Run ESLint
# Database (Drizzle ORM)
pnpm db:generate # Generate migration files from schema changes
pnpm db:migrate # Apply migrations to database
pnpm db:push # Push schema directly (dev only, skips migrations)
pnpm db:studio # Open Drizzle Studio UI (database GUI)
# Utilities
pnpm screenshots:capture # Capture OpenGraph images
```
### Database Workflow
1. **Modify schema**: Edit `lib/db/schema.ts`
2. **Generate migration**: `pnpm db:generate` (creates timestamped SQL in `lib/db/migrations/`)
3. **Apply migration**: `pnpm db:migrate` (applies to `DATABASE_URL`)
4. **Quick dev push**: `pnpm db:push` (bypasses migrations, use sparingly)
### Adding a New AI Model
1. Edit `lib/ai/models.json`
2. Add model definition with pricing:
```json
{
"id": "anthropic/claude-3.5-sonnet",
"name": "Claude 3.5 Sonnet",
"provider": "Anthropic",
"type": "paid",
"contextWindow": 200000,
"maxTokens": 8192,
"inputCostPer1M": 3.0,
"outputCostPer1M": 15.0,
"description": "Most intelligent model"
}
```
3. Model will be auto-loaded by `lib/ai/models.ts`
### Creating a New API Route
1. Create file: `app/api/[route]/route.ts`
2. Export HTTP method handlers:
```typescript
export async function GET(request: Request) {
// Handler logic
return NextResponse.json({ data });
}
```
3. Use `getUser()` for authentication
4. Return `NextResponse.json()` with proper status codes
## Project Structure
```
my-saas-app/
├── app/ # Next.js App Router
│ ├── (marketing)/ # Public pages (/, /pricing, /features)
│ │ └── (legal)/ # Legal pages (/privacy, /terms)
│ ├── (protected)/ # Auth-protected routes
│ │ └── dashboard/ # User dashboard
│ │ ├── page.tsx # Dashboard home
│ │ ├── chat/ # AI chat interface
│ │ ├── account/ # Account settings
│ │ ├── prompts/ # Saved prompts
│ │ ├── test-prompt/ # Test prompt sandbox
│ │ └── components/ # Dashboard components
│ ├── auth/ # Authentication flows
│ ├── setup/ # Setup wizard (dev only)
│ └── api/ # API routes
│ ├── auth/ # Auth callback
│ ├── conversations/ # Chat CRUD
│ ├── prompts/ # Saved prompts CRUD
│ ├── stripe/ # Stripe webhooks & checkout
│ ├── cron/ # Scheduled jobs
│ ├── health/ # Health check
│ └── contact/ # Contact form
├── components/ # React components
│ ├── ui/ # shadcn/ui components
│ ├── magicui/ # Animated components
│ └── dashboard/ # Dashboard components
├── lib/ # Core library code
│ ├── actions/ # Server actions
│ ├── ai/ # AI integration
│ │ ├── openrouter.ts # OpenRouter client
│ │ ├── models.ts/json # Model definitions
│ │ └── context-manager.ts # Context window management
│ ├── db/ # Database layer
│ │ ├── schema.ts # Drizzle schema
│ │ ├── queries/ # Query functions
│ │ └── migrations/ # SQL migrations
│ ├── payments/ # Stripe integration
│ ├── prompts/ # System prompts
│ ├── supabase/ # Supabase clients
│ └── utils/ # Shared utilities
├── prompts/ # System prompt JSON files
├── public/ # Static assets
├── .env.local # Environment variables (create from .env.example)
├── drizzle.config.ts # Drizzle ORM configuration
├── middleware.ts # Next.js middleware (auth, session refresh)
├── next.config.ts # Next.js configuration
├── tailwind.config.ts # Tailwind CSS configuration
├── tsconfig.json # TypeScript configuration
├── CLAUDE.md # Claude Code developer guide
└── README.md # This file
```
## Key Features Explained
### Context Window Management
The app automatically manages token limits to prevent context overflow:
1. **Token Estimation**: Uses `gpt-tokenizer` for accurate token counts
2. **Smart Summarization**: When conversation reaches 70% of model's max tokens:
- Keeps last 10 messages (recent context)
- Summarizes older messages using the same AI model
- Replaces old messages with summary (reduces tokens significantly)
3. **Model-Specific Limits**: Each model has its own context window defined in `models.json`
### Credit System
**Unsubscribed Users:**
- Cannot access AI features
- Must subscribe to use the service
- Redirected to pricing page
**Trial Users** (`subscriptionStatus: 'trialing'`):
- $1.00 trial credit upon subscription
- 7-day trial (monthly) or 14-day trial (yearly)
- Low credit warning at $0.25 remaining
- Can upgrade early to receive full plan credits immediately
**Paid Users** (`subscriptionStatus: 'active'`):
- Credits allocated based on Stripe product metadata (`ai_credits_amount`)
- Deducted based on actual OpenRouter API costs
- Monthly reset on subscription anniversary
- Yearly reset via cron job
### Token Tracking
All AI usage is logged to `token_usage_logs` table with:
- Separate input/output token counts
- Input/output/total costs (6 decimal precision)
- Model used and timestamp
- Survives conversation deletion (audit trail)
### Artifact System
Split-view display for generated content:
- **Desktop (≥1024px)**: 50/50 split view (chat | artifact)
- **Mobile (<1024px)**: Overlay with tabs
- Responsive grid with automatic breakpoint handling
- Markdown rendering with syntax highlighting
### Early Trial Upgrade
Trial users can upgrade to their current plan immediately:
1. Click "Upgrade to Full Plan" button
2. Triggers `endTrialEarlyAction()` server action
3. Calls Stripe API with `trial_end: 'now'`
4. Charges payment method immediately
5. Status changes from 'trialing' to 'active'
6. Credits reset to full plan amount
## Deployment
### Vercel (Recommended)
1. **Connect repository**
- Import project in Vercel dashboard
- Connect GitHub/GitLab/Bitbucket
2. **Configure environment variables**
- Add all variables from `.env.local`
- Set `SETUP_COMPLETE=true`
- Add `CRON_SECRET` for scheduled functions
3. **Configure cron jobs**
Create `vercel.json` in project root:
```json
{
"crons": [
{
"path": "/api/cron/reset-yearly-credits",
"schedule": "0 0 1 * *"
}
]
}
```
4. **Deploy**
```bash
vercel --prod
```
### Docker
1. **Build image**
```bash
docker build -t my-saas-app .
```
2. **Run container**
```bash
docker run -p 3000:3000 --env-file .env.local my-saas-app
```
3. **Docker Compose** (with PostgreSQL)
```bash
docker-compose up -d
```
### Google Cloud Run
1. **Build and push image**
```bash
gcloud builds submit --tag gcr.io/PROJECT-ID/my-saas-app
```
2. **Deploy to Cloud Run**
```bash
gcloud run deploy my-saas-app \
--image gcr.io/PROJECT-ID/my-saas-app \
--platform managed \
--region us-central1 \
--allow-unauthenticated \
--set-env-vars="NODE_ENV=production,SETUP_COMPLETE=true" \
--set-secrets="DATABASE_URL=database-url:latest"
```
## Scheduled Jobs (Cron)
### Yearly Credit Reset
**Endpoint:** `/api/cron/reset-yearly-credits`
**Purpose:** Reset AI credits for yearly subscription users on their anniversary date
**Schedule:** Monthly (1st of every month at 00:00 UTC)
**Cron Expression:** `0 0 1 * *`
**Security:** Requires `x-cron-secret` header matching `CRON_SECRET` environment variable
**Setup on Vercel:**
```json
{
"crons": [
{
"path": "/api/cron/reset-yearly-credits",
"schedule": "0 0 1 * *"
}
]
}
```
## Security Considerations
### Authentication
- Supabase Auth with session-based authentication
- Middleware refreshes sessions on every request
- Protected routes check for valid user session
- Activity logging for security audit trail
### API Security
- Stripe webhook signature verification
- Cron job authentication via secret header
- Server actions validate user authentication
- Environment variables never exposed to client
### Credit System
- All costs deducted server-side (never trust client)
- Token usage logged permanently (audit trail)
- Stripe handles payment processing (PCI compliant)
- Webhook events validate subscription status
### Data Privacy
- User data isolated by user ID (row-level filtering)
- Passwords hashed by Supabase Auth
- Activity logs track user actions
- GDPR-compliant data handling
## Troubleshooting
### Setup Wizard Not Appearing
**Solution:** Ensure `SETUP_COMPLETE=false` and `NODE_ENV=development` in `.env.local`
### Database Connection Errors
**Check:**
1. `DATABASE_URL` format: `postgresql://user:password@host:PORT/database`
2. Supabase project is not paused
3. Database pooler is enabled (use pooler URL)
4. IP allowlist if using restricted access
### Stripe Webhook Failures
**Debug:**
1. Check webhook signing secret matches `.env.local`
2. Verify webhook endpoint is accessible (use Stripe CLI for local testing)
3. Check webhook logs in Stripe Dashboard
4. Ensure all required events are subscribed
### OpenRouter API Errors
**Common issues:**
1. Invalid API key
2. Insufficient credits in OpenRouter account
3. Model not available or deprecated
4. Rate limiting (429 errors)
### Credit Not Deducting
**Check:**
1. Token usage logs are being created (`token_usage_logs` table)
2. `deductAICredits()` function is called after AI response
3. User has `aiCreditsBalance > 0`
4. Webhook processed subscription correctly
## Support
For questions or issues:
- **Documentation:** Check `CLAUDE.md` for developer guide
- **GitHub Issues:** Report bugs or feature requests
- **Contact Form:** Use in-app contact form on marketing site
## License
[Add your license here]
## Acknowledgments
Built with:
- [Next.js](https://nextjs.org/) - React framework
- [Supabase](https://supabase.com/) - Backend as a Service
- [Stripe](https://stripe.com/) - Payment processing
- [OpenRouter](https://openrouter.ai/) - Multi-model AI API
- [shadcn/ui](https://ui.shadcn.com/) - UI components
- [Drizzle ORM](https://orm.drizzle.team/) - Database ORM
- [Tailwind CSS](https://tailwindcss.com/) - CSS framework