Deployment Guide
Important Notice: This documentation is maintained as a reference for AI assistants and internal development. External contributions are not accepted.
Complete guide to deploying All My Chats to production on Google Cloud Run with Neon PostgreSQL database and GitHub Actions CI/CD.
Table of Contents
- Quick Reference ⭐ Start here
- Deployment Architecture
- Prerequisites
- Neon Database Setup
- Google Cloud Setup
- GitHub Actions CI/CD Setup
- Environment Configuration
- Database Migration
- Deployment
- Post-Deployment Verification
- Monitoring & Maintenance
- Troubleshooting
- Cost Summary
Quick Reference
One-page summary for quick deployment tasks.
Pre-Deployment Checklist (30 min)
- Generate secrets:
openssl rand -base64 32 - Create Neon account at https://console.neon.tech
- Create Google Cloud project at https://console.cloud.google.com
- Create GitHub repository with your code
Required Services (Free to Start)
| Service | Link | Free Tier |
|---|---|---|
| Neon Database | https://console.neon.tech | 0.5 GB, 100 CU-hrs |
| Google Cloud Run | https://console.cloud.google.com | 2M requests/month |
| GitHub Actions | https://github.com | Free for public repos |
Required Secrets (GitHub)
| Secret | Value |
|---|---|
GOOGLE_CREDENTIALS | Service account JSON key |
GOOGLE_PROJECT_ID | Your project ID |
GOOGLE_REGION | asia-southeast1 (Singapore) |
DATABASE_URL | Neon connection string |
BETTER_AUTH_SECRET | openssl rand -base64 32 |
APP_URL | Your production URL |
VITE_BETTER_AUTH_URL | Same as APP_URL |
VITE_ALLOWED_ORIGINS | Your domain |
GLM_API_KEY | Zhipu AI API key |
Deployment Steps (Automated)
- Push to
feature/ready-to-deploy→ GitHub Actions auto-deploys - Wait ~5-10 minutes for build & deployment
- Access at:
https://your-app-xxxxx.a.run.app - Run migrations:
DATABASE_URL="..." npm run db:migrate:run - Test: signup, login, import messages
Common Issues Quick Fix
| Issue | Solution |
|---|---|
| Static files 404 | Check server.js serves /assets/ |
| Env vars missing | Check .dockerignore has !.env.production |
| Auth fails | Check BETTER_AUTH_SECRET, VITE_BETTER_AUTH_URL |
| Wrong credentials | Use Service Account key, not OAuth |
| Region mismatch | Verify GOOGLE_REGION matches service region |
| Database fails | Check DATABASE_URL, Neon IP allowlist |
Cost Estimate
| Resource | Monthly Cost |
|---|---|
| Neon DB (1.25 GB) | ~$0.44 |
| Cloud Run (2M req) | $0-5 |
| Total | ~$0.44-5.50 |
Note: Neon invoices under $0.50 are NOT collected!
Deployment Architecture
What is All My Chats?
All My Chats is an AI-powered message analysis and categorization tool for WhatsApp conversations. It automatically categorizes and analyzes messages using multiple LLM providers (Claude, GPT-4, GLM).
Current Deployment Architecture
┌─────────────────────────────────────────────────┐
│ GitHub Repository │
│ (whatsapp-message-AI-analysis-agent) │
└────────────────┬────────────────────────────────┘
│ Push to feature/ready-to-deploy
▼
┌─────────────────────────────────────────────────┐
│ GitHub Actions CI/CD │
│ (Build, Push to Artifact Registry) │
└────────────────┬────────────────────────────────┘
│ Deploy
▼
┌─────────────────────────────────────────────────┐
│ Google Cloud Run │
│ (All My Chats - TanStack Start) │
│ Region: asia-southeast1 (Singapore) │
└────────┬────────────────────────────────────────┘
│ Connect
▼
┌─────────────────────────────────────────────────┐
│ Neon Database │
│ (PostgreSQL 17) │
│ Region: ap-southeast-1 (Singapore) │
│ - Serverless, Auto-scaling │
│ - Branching, Time travel │
└─────────────────────────────────────────────────┘
Deployment Timeline
- Neon Database Setup: 10-15 minutes
- Google Cloud Setup: 20-30 minutes
- GitHub Actions CI/CD: 15-20 minutes
- Environment Configuration: 10 minutes
- First Deployment: 5-10 minutes (automated)
- Total: ~1.5 hours for first deployment
Region Selection
| Component | Region | Why |
|---|---|---|
| Neon Database | ap-southeast-1 (Singapore) | Closest to India users (~50-80ms latency) |
| Cloud Run | asia-southeast1 (Singapore) | Same region as DB, closest to India users |
Prerequisites
Required Accounts
- GitHub Account - With access to your repository
- Google Cloud Account - Sign up at https://console.cloud.google.com
- Free tier: $300 credit for 90 days
- Neon Account - Sign up at https://console.neon.tech
- Free tier: 0.5 GB storage, 100 CU-hours compute
Required Tools
# Check if you have these installed
git --version # Should be 2.0+
node --version # Should be 18+
npm --version # Should be 9+
Generate Required Secrets
Open your terminal and generate the essential secret:
# Generate Better Auth secret (REQUIRED)
openssl rand -base64 32
# Save this output - you'll need it for BETTER_AUTH_SECRET
Neon Database Setup
IMPORTANT: Complete database setup BEFORE configuring environment variables or deploying.
Step 1: Create Neon Account
- Go to Neon Console
- Sign up with GitHub, Google, or email
- Verify your email address
Step 2: Create Neon Project
- Click "Create a project"
- Configure:
| Field | Value | Notes |
|---|---|---|
| Project Name | allmychats | Descriptive name |
| Database Name | neondb (default) | Can leave as default |
| PostgreSQL Version | 17 | Latest stable version |
| Region | ap-southeast-1 (Singapore) | Closest to India users |
| Pricing Plan | Free (to start) | Upgrade to Launch if needed |
- Click "Create Project"
- Wait for provisioning (~30 seconds)
Step 3: Get Connection String
- In Neon Console, go to your project
- Click "Connection Details" (or SQL Editor)
- Copy the connection string:
postgresql://neondb_owner:[YOUR-PASSWORD]@ep-xxx.ap-southeast-1.aws.neon.tech/neondb?sslmode=require
- Save this securely - you'll need it for
DATABASE_URL
Storage Breakdown (MVP: 100 users, 100K messages)
| Component | Size |
|---|---|
| User data & sessions | ~1 MB |
| Messages (100K) | ~300 MB |
| Message embeddings (vectors) | ~600 MB ⭐ Largest |
| Categories, tags, metadata | ~30 MB |
| Database indexes & overhead | ~310 MB |
| Total | ~1.25 GB |
Note:
messageEmbedding(vector storage) is the largest contributor at ~600 MB.
Cost: ~$0.44/month (1.25 GB × $0.35/GB) - Likely FREE since invoices under $0.50 are not collected!
Google Cloud Setup
Step 1: Create Google Cloud Project
- Go to Google Cloud Console
- Click "Select a project" → "New Project"
- Enter project details:
| Field | Value |
|---|---|
| Project Name | allmychats |
| Organization | (leave blank for personal) |
| Location | No organization |
- Click "Create"
- Wait for project to be created (~30 seconds)
Step 2: Enable Required APIs
- Go to APIs & Services → Library
- Search for and enable these APIs:
✓ Cloud Run API
✓ Cloud Build API
✓ Artifact Registry API
✓ Cloud Storage JSON API (optional, for file storage)
Step 3: Create Artifact Registry (for Docker images)
- Go to Artifact Registry → Repositories
- Click "Create Repository"
- Configure:
| Field | Value |
|---|---|
| Name | docker-repo |
| Format | Docker |
| Location type | Region |
| Region | asia-southeast1 (Singapore) |
| Mode | Standard |
- Click "Create"
Step 4: Set Up Google Cloud Billing
- Go to Billing → Manage
- Link a payment method (required for Cloud Run)
- Note: Google Cloud offers $300 free credit for new accounts
Step 5: Custom Domain Setup (Optional)
Set up custom domains to replace the auto-generated xxxxx.run.app URL.
Recommended Domain Structure:
| Domain | Purpose | Where to Deploy |
|---|---|---|
allmychats.online | Landing page | Vercel (static site) |
app.allmychats.online | Full product (frontend + API) | Cloud Run |
Note: You don't need a separate
api.subdomain because TanStack Start serves both frontend and API routes from the same deployment.
GitHub Actions CI/CD Setup
Step 1: Create Google Service Account
- Go to IAM & Admin → Service Accounts
- Click "Create Service Account"
- Configure:
| Field | Value |
|---|---|
| Service account name | github-actions-deploy |
| Service account description | "CI/CD deploy for Cloud Run" |
- Click "Create and Continue"
- Add roles:
✓ Cloud Run Admin
✓ Cloud Run Service Agent
✓ Service Account User
✓ Artifact Registry Reader
- Click "Done"
Step 2: Create Service Account Key (⚠️ CRITICAL)
⚠️ VERY IMPORTANT: You need a Service Account key for deployment, NOT an OAuth client secret!
- Click on the service account you just created
- Go to Keys tab
- Click "Add Key" → "Create new key"
- Select JSON format
- Click "Create"
- Download and save the JSON file securely
The JSON file should look like this:
{
"type": "service_account",
"project_id": "your-project-id",
"private_key_id": "...",
"private_key": "-----BEGIN PRIVATE KEY-----\n...",
"client_email": "[email protected]",
"client_id": "123456789",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token"
}
⚠️ DO NOT use the OAuth client secret JSON!
Step 3: Add GitHub Secrets
- Go to your GitHub repository
- Click Settings → Secrets and variables → Actions
- Click "New repository secret"
- Add the following secrets:
Required Secrets
| Secret Name | Value | Notes |
|---|---|---|
GOOGLE_CREDENTIALS | Content of the JSON key file (paste entire JSON) | Multi-line JSON from Service Account |
GOOGLE_PROJECT_ID | allmychats | Your Google Cloud project ID |
GOOGLE_REGION | asia-southeast1 | Cloud Run region (⚠️ verify matches your service) |
DATABASE_URL | Your Neon connection string | PostgreSQL connection string |
BETTER_AUTH_SECRET | Your 32-char random secret | Generate with: openssl rand -base64 32 |
APP_URL | Your production URL (e.g., https://allmychats.online) | Public URL of your app |
GLM_API_KEY | Your Zhipu AI API key | Required for AI features |
VITE_BETTER_AUTH_URL | Your production URL | Same as APP_URL |
VITE_ALLOWED_ORIGINS | Your domain(s), comma-separated | e.g., https://allmychats.online |
Step 4: Configure .dockerignore (⚠️ CRITICAL)
⚠️ IMPORTANT: Your .dockerignore file must allow .env.production during Docker build!
Create or update .dockerignore file in your project root:
# Dependencies
node_modules
# Build outputs
.output
dist
# Environment files
.env*
!.env.example
!.env.production # <-- This line is CRITICAL for builds!
# Git
.git
.gitignore
# IDE
.vscode
.idea
# Testing
playwright-report
test-results
# Misc
*.md
*.log
temp
.DS_Store
Thumbs.db
Environment Configuration
Environment Variables Reference
Required Variables (Must Set)
# Database (Neon)
DATABASE_URL=postgresql://neondb_owner:[PASSWORD]@ep-xxx.ap-southeast-1.aws.neon.tech/neondb?sslmode=require
# Authentication
BETTER_AUTH_SECRET=your-32-char-random-secret
Optional Variables (Add as Needed)
# LLM Providers (for AI features)
ANTHROPIC_API_KEY=sk-ant-xxxxx
OPENAI_API_KEY=sk-xxxxx
GLM_API_KEY=xxxxx
# File Storage (Cloudflare R2)
R2_ACCESS_KEY_ID=xxxxx
R2_SECRET_ACCESS_KEY=xxxxx
R2_ACCOUNT_ID=xxxxx
R2_BUCKET_NAME=allmychats-uploads
# Google OAuth
GOOGLE_CLIENT_ID=xxxxx.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=GOCSPX-xxxxx
# Stripe Payments
STRIPE_SECRET_KEY=sk_live_xxxxx
STRIPE_WEBHOOK_SECRET=whsec_xxxxx
Database Migration
IMPORTANT: Run migrations BEFORE deploying the application to avoid errors.
Migration Overview
The project uses Drizzle ORM with migration files in drizzle/ directory.
Step 1: Review Migration Files
# List all migrations
ls -la drizzle/*.sql
# Preview a migration (optional)
cat drizzle/0014_rapid_stature.sql
Step 2: Run Migrations (Recommended Before Deployment)
# Set your production DATABASE_URL
export DATABASE_URL="postgresql://user:password@host:5432/dbname"
# Run migrations
npm run db:migrate:run
# Expected output:
# ✅ Migrations completed successfully
Step 3: Verify Migration Success
# Connect to database via Neon Console SQL Editor
# Or use psql
psql $DATABASE_URL
# Check migrations table
SELECT * FROM __drizzle_migrations ORDER BY created_at;
# List tables
\dt
Deployment
Automatic Deployment (Recommended)
When you push to master, main, or feature/ready-to-deploy:
# 1. Make your changes
git add .
git commit -m "Add new feature"
# 2. Push to branch
git push origin feature/ready-to-deploy
What happens automatically:
- ✅ GitHub Actions triggers on push
- ✅ Code is checked out
- ✅ Docker image is built
- ✅ Image is pushed to Google Artifact Registry
- ✅ Cloud Run deployment is updated
- ✅ New revision is deployed with zero downtime
Manual Deployment
Option A: Trigger GitHub Actions Manually
- Go to GitHub repository
- Click Actions tab
- Select "Deploy to Google Cloud Run" workflow
- Click "Run workflow"
- Select branch and click "Run workflow"
Option B: Using gcloud CLI
# Deploy from local machine
gcloud run deploy allmychats \
--image asia-southeast1-docker.pkg.dev/allmychats/docker-repo/allmychats:latest \
--region asia-southeast1 \
--platform managed \
--allow-unauthenticated
Post-Deployment Verification
Step 1: Get Your App URL
After successful deployment, GitHub Actions will show:
Deployment URL: https://allmychats-xxxxx.a.run.app
Or find it in Google Cloud Console:
- Go to Cloud Run → your service
- Click on the service URL at the top
Step 2: Verify Deployment is Running
- In Google Cloud Console → Cloud Run → your service
- Check status is "Running" (green checkmark)
- Click on Logs tab
- Look for:
Server running on port 3000
Database connected successfully
Step 3: Test Application Health
Visit your app URL in browser:
https://allmychats-xxxxx.a.run.app
Expected:
- ✅ Landing page loads
- ✅ No console errors (browser DevTools)
- ✅ "Sign Up" button visible
Step 4: Test User Registration
- Click "Sign Up"
- Enter email and password
- Submit form
- Expected:
- ✅ Account created successfully
- ✅ Redirected to dashboard
- ✅ No errors
Monitoring & Maintenance
Neon Dashboard Monitoring
- Go to Neon Console
- View your project dashboard
- Monitor:
| Metric | What to Watch |
|---|---|
| Storage Usage | Approaching 1.5 GB (consider cleanup) |
| Active Compute | Approaching 100 CU-hours (may exceed free tier) |
| Request Count | Spikes indicate heavy usage |
Cloud Run Monitoring
- Go to Cloud Run → your service → Metrics tab
- View:
- Request count
- Request latency
- CPU/memory usage
- Instance count
Scaling Configuration
View current scaling:
gcloud run services describe allmychats \
--region asia-southeast1 \
--format 'value(spec.template.spec.scaling)'
Update scaling:
# Set minimum and maximum instances
gcloud run services update allmychats \
--min-instances 0 \
--max-instances 10 \
--region asia-southeast1
# Enable autoscaling
gcloud run services update allmychats \
--scaling-mode automatic \
--region asia-southeast1
Scaling Recommendations
| Traffic Pattern | Min Instances | Max Instances | Notes |
|---|---|---|---|
| Development | 0 | 1 | Scale to zero when idle |
| MVP (100 users) | 0 | 5 | Auto-scale based on traffic |
| Growth (1K users) | 1 | 10 | Keep 1 warm for faster response |
| Production (10K+) | 2 | 100 | Multiple instances for HA |
Troubleshooting
Critical Deployment Issues (Real-World Cases)
❌ Issue 1: Static Assets Return 404 Errors
Symptoms:
GET https://allmychats.online/assets/main-BgDCIyLK.css net::ERR_ABORTED 404
GET https://allmychats.online/site.webmanifest 404
Root Cause:
The server.js production server was not configured to serve static files (CSS, JS, manifest). It only handled API routes and SSR, leaving all static assets to return 404.
Solution:
Update server.js to include static file serving functionality.
❌ Issue 2: Environment Variables Blocked by .dockerignore
Symptoms:
Error: Environment validation failed
- DATABASE_URL: Invalid input: expected string, received undefined
- BETTER_AUTH_SECRET: Invalid input: expected string, received undefined
Root Cause:
The .dockerignore file had a .env* pattern that excluded .env.production.
Solution:
Add an exception for .env.production:
.env*
!.env.example
!.env.production # <-- CRITICAL: Allow this file during builds!
❌ Issue 3: Wrong Google Credentials Type (OAuth vs Service Account)
Symptoms:
Error: provided credential is not a valid Google Service Account Key JSON
Root Cause: Using OAuth client credentials instead of Service Account credentials for deployment.
Solution:
- Go to IAM & Admin → Service Accounts
- Select your service account → Keys tab
- Click "Add Key" → "Create new key" → JSON
- Download and use this file for
GOOGLE_CREDENTIALSsecret
❌ Issue 4: Region Mismatch Between Deployment and Cloud Run Service
Symptoms:
Error: Resource 'projects/allmychats/regions/asia-south1/services/allmychats' not found
Root Cause:
The GitHub Actions workflow was deploying to asia-south1 (Mumbai), but the Cloud Run service was created in asia-southeast1 (Singapore).
Solution:
Update GOOGLE_REGION secret in GitHub to match your existing service.
❌ Issue 5: Authentication Failures (POST Requests Return 500/403)
Symptoms:
POST https://allmychats.online/api/auth/register 500
POST https://allmychats.online/api/auth/sign-in/social 403
Root Causes:
- Missing
duplexoption in Node.js 18+ Request - Missing
trustedOriginsin Better Auth config - Wrong Google OAuth redirect URI
Solutions:
Fix 1: Add duplex to server.js
const webReq = new Request(url, {
method: req.method,
headers,
body: req.method !== "GET" && req.method !== "HEAD" ? req : undefined,
duplex: req.method !== "GET" && req.method !== "HEAD" ? "half" : undefined,
});
Fix 2: Configure Better Auth
export const auth = betterAuth({
secret: privateEnv.BETTER_AUTH_SECRET,
database: drizzleAdapter(database, { provider: "pg" }),
baseURL: process.env.APP_URL || process.env.VITE_BETTER_AUTH_URL || undefined,
trustedOrigins: (process.env.VITE_ALLOWED_ORIGINS || process.env.APP_URL || "")
.split(",")
.map((o) => o.trim())
.filter(Boolean),
});
Cost Summary
Monthly Cost Breakdown (Estimated)
| Service | Monthly Cost | Notes |
|---|---|---|
| Neon Database | ~$0.44 | 1.25 GB × $0.35/GB |
| Cloud Run | ~$0-5 | 2M requests free, then ~$0.40/M |
| Artifact Registry | $0 | 0.5 GB free |
| Cloud Storage (optional) | $0 | 5 GB free |
| Total | ~$0.44-5.50/month | Depends on traffic |
Key Pricing Notes
Neon Database:
- Free tier: 0.5 GB storage, 100 CU-hrs compute
- Your app uses ~1.25 GB (exceeds free tier)
- Launch plan: $0.35/GB-month, $0.106/CU-hour
- Invoices under $0.50 are NOT collected - you may pay nothing!
Cloud Run:
- Free tier: 2M requests/month, 200K vCPU-seconds, 400K GB-seconds
- Paid: $0.40 per million requests after free tier
- Network: 10 GB egress free, then $0.12/GB
Total estimated cost: $0-5.50/month depending on traffic
Security Checklist
Before considering deployment "complete", verify:
-
BETTER_AUTH_SECRETis strong (32+ random characters) -
DATABASE_URLcontains strong password - All secrets stored in GitHub Secrets (not in code)
-
.env.productionNOT committed to git -
.env.localNOT committed to git - Google service account has minimum required permissions
- HTTPS enabled (automatic on Cloud Run)
- CORS configured correctly
- Secrets stored securely (1Password, etc.)
Last Updated: 2025-01-21 Version: Production (Google Cloud Run + Neon + GitHub Actions) For: All My Chats