A production-ready full-stack template for rapid side project development with React, TypeScript, Express, PostgreSQL, Firebase Auth, Stripe payments, and AI chat.
-
Neon Database (required)
- Sign up at neon.tech (free tier available)
- Create a new project and database
- Copy the connection string (it should look like
postgresql://user:pass@ep-xxxxx.region.aws.neon.tech/dbname)
⚠️ Important: This project uses@neondatabase/serverlesswhich requires Neon's WebSocket support. Local PostgreSQL will not work without code modifications. -
Firebase (required)
- Create a project at Firebase Console
- Enable Authentication → Sign-in method → Enable Email/Password and Google
- Enable Storage
- Get your configuration:
- Go to Project Settings → General → Your apps
- Add a Web app if you haven't already
- Copy all the config values (apiKey, authDomain, projectId, etc.)
- Go to Project Settings → Service Accounts → Generate new private key
- Save the JSON file for server-side authentication
# 1. Install dependencies
npm install
# 2. Configure environment variables
cp .env.example .env
# Edit .env and fill in REQUIRED values (see .env.example for guidance)
# 3. Initialize database
npm run db:push
# 4. Start development server
npm run devThe app will be available at http://localhost:5000 (configurable via PORT env variable)
These must be configured for the app to run:
DATABASE_URL- Neon PostgreSQL connection stringSESSION_SECRET- Random string for session securityGOOGLE_APPLICATION_CREDENTIALSorFIREBASE_SERVICE_ACCOUNT_KEY- Firebase Admin SDK credentialsVITE_FIREBASE_PROJECT_ID- Your Firebase project IDVITE_FIREBASE_API_KEY- Firebase web API keyVITE_FIREBASE_AUTH_DOMAIN- Firebase auth domainVITE_FIREBASE_MESSAGING_SENDER_ID- Firebase messaging sender IDVITE_FIREBASE_APP_ID- Firebase app IDFIREBASE_STORAGE_BUCKET- Firebase storage bucket name
See .env.example for complete configuration including optional services (Stripe, SendGrid, PostHog, OpenAI).
Make sure to set these environment variables:
# Stripe Configuration
STRIPE_SECRET_KEY=sk_test_... # Your Stripe secret key
STRIPE_WEBHOOK_SECRET=whsec_... # Webhook endpoint secret from Stripe Dashboard
STRIPE_PRICE_ID_PRO=price_... # Price ID for your Pro subscription
# Client-side
VITE_STRIPE_PUBLIC_KEY=pk_test_... # Your Stripe publishable key
# SendGrid (email)
SENDGRID_API_KEY=SG.... # Server-side only
SENDGRID_FROM=verified@yourdomain.com # Verified sender address
# Analytics (PostHog)
POSTHOG_API_KEY=phc_...
POSTHOG_HOST=https://us.i.posthog.com
# OpenAI (AI chat)
OPENAI_API_KEY=sk-...
# Frontend origin (prod only; used by CORS and redirect validation)
FRONTEND_URL=https://yourapp.com- Simple Upgrade Flow: Users click "Upgrade to Pro" → Redirected to Stripe Checkout
- Automatic Fulfillment: Webhooks handle subscription activation automatically
- Success Handling: Users return to dashboard with success confirmation
- Subscription Management: Users can manage subscriptions through Stripe's billing portal
POST /api/create-checkout-session- Creates a new Stripe Checkout sessionPOST /api/create-portal-session- Creates a Stripe billing portal sessionPOST /api/webhook- Handles Stripe webhook events
Health and readiness:
GET /health- Liveness probe (always 200)GET /ready- Readiness probe (checks DB connectivity)
checkout.session.completed- Activates subscription after successful paymentcustomer.subscription.updated- Handles subscription status changescustomer.subscription.deleted- Downgrades user to free planinvoice.payment_succeeded- Renews subscriptioninvoice.payment_failed- Logs failed payments
- Use Stripe's test mode with test cards
- Use Stripe CLI for webhook testing:
stripe listen --forward-to localhost:3000/api/webhook - Test successful payments with card
4242 4242 4242 4242 - Test failed payments with card
4000 0000 0000 0002
Use stripe listen --forward-to localhost:5000/api/webhook for testing webhooks locally
✅ Simplified Code: Removed 400+ lines of payment method management
✅ Better UX: Professional checkout experience
✅ Mobile Optimized: Works perfectly on all devices
✅ Security: No sensitive payment data in frontend
✅ International: Built-in support for multiple payment methods
✅ Promotion Codes: Built-in support for discount codes
✅ Tax Calculation: Automatic tax calculation
npm install
npm run db:push
npm run devMake sure to:
- Set production Stripe keys
- Configure webhook endpoint in Stripe Dashboard
- Set
STRIPE_WEBHOOK_SECRETfrom webhook settings - Configure Stripe billing portal at Settings > Billing > Customer portal in Stripe Dashboard
- Content Security Policy (CSP): In production, inline scripts/styles are blocked. Only required third-party origins are allowed (Stripe, Google Auth/Fonts, Firebase, PostHog). Development permits inline for Vite.
- Rate Limiting: A global
/apilimiter enforces 500 requests per 15 minutes, keyed by authenticated user when available, otherwise IP. AI chat and thread routes also have per-route limits. - Safe Downloads: File downloads use a sanitized filename and RFC 5987 headers to prevent header injection.
- Stripe Redirects:
success_urlandcancel_urlare validated against trusted origins (fromFRONTEND_URLin production). Unknown origins fall back to safe defaults. - SendGrid Sender: Emails use
SENDGRID_FROM(must be a verified sender), not a hardcoded address.
Production CORS is strict. Ensure FRONTEND_URL matches your deployed domain. Development allows http://localhost:5173, http://localhost:5000, and http://127.0.0.1:5173.