Add production deployment configuration

Torey Heinz committed Aug 24, 2025
commit d1491daf7761abb52c975d1edc53a6c8c28a3a6e
Showing 3 changed files with 233 additions and 0 deletions
DEPLOYMENT.md +165 -0
@@ @@ -0,0 +1,165 @@
+ # Deployment Guide for qrurl.us
+
+ ## Prerequisites
+
+ 1. **Cloudflare Account** with:
+ - Workers subscription (free tier works)
+ - R2 enabled
+ - Pages enabled
+ - Domain `qrurl.us` added to Cloudflare
+
+ 2. **GitHub Repository**: https://github.com/toreyheinz/qrurl
+
+ ## Setup Steps
+
+ ### 1. Configure Cloudflare API Token
+
+ Create a Cloudflare API token with these permissions:
+ - Account: Cloudflare Workers Scripts:Edit
+ - Account: Cloudflare Pages:Edit
+ - Account: D1:Edit
+ - Account: Workers R2 Storage:Edit
+ - Account: Workers KV Storage:Edit
+ - Zone: DNS:Edit (for qrurl.us)
+
+ ### 2. Add GitHub Secrets
+
+ Go to GitHub repo → Settings → Secrets → Actions and add:
+
+ - `CLOUDFLARE_API_TOKEN`: Your Cloudflare API token
+ - `CLOUDFLARE_ACCOUNT_ID`: b253e6fbfd2f7757cadd0386de5bde3f
+
+ ### 3. Configure Cloudflare Environment
+
+ #### Workers Secrets (via Dashboard or CLI):
+ ```bash
+ # Set production secrets
+ npx wrangler secret put JWT_SECRET --env production
+ npx wrangler secret put EMAIL_API_KEY --env production
+ npx wrangler secret put AUTHORIZED_EMAILS --env production
+ ```
+
+ #### Initialize Production Database:
+ ```bash
+ # Run database migrations on production
+ npm run db:init:remote
+ ```
+
+ ### 4. Set Up Custom Domains
+
+ #### For API (Workers):
+ 1. Go to Cloudflare Dashboard → Workers & Pages → qrurl
+ 2. Settings → Triggers → Custom Domains
+ 3. Add: `api.qrurl.us`
+
+ #### For Frontend (Pages):
+ 1. Go to Cloudflare Dashboard → Workers & Pages → qrurl-frontend
+ 2. Custom domains → Add domain
+ 3. Add: `qrurl.us` and `www.qrurl.us`
+
+ ### 5. Create Cloudflare Pages Project
+
+ ```bash
+ # One-time setup for Pages project
+ npx wrangler pages project create qrurl-frontend --production-branch main
+ ```
+
+ ### 6. DNS Configuration
+
+ Add these DNS records in Cloudflare:
+
+ ```
+ Type Name Content
+ A @ 192.0.2.1 (Proxied - placeholder for Pages)
+ CNAME www qrurl.us (Proxied)
+ CNAME api qrurl.workers.dev (Proxied - or use Workers custom domain)
+ ```
+
+ ## Deployment Process
+
+ ### Automatic Deployment
+
+ Push to `main` branch triggers automatic deployment:
+
+ ```bash
+ git push origin main
+ ```
+
+ This will:
+ 1. Deploy backend to Cloudflare Workers
+ 2. Build and deploy frontend to Cloudflare Pages
+ 3. Update both production environments
+
+ ### Manual Deployment
+
+ #### Backend:
+ ```bash
+ npm run deploy
+ ```
+
+ #### Frontend:
+ ```bash
+ cd frontend
+ npm run build
+ npx wrangler pages deploy dist --project-name qrurl-frontend
+ ```
+
+ ## Environment Variables
+
+ ### Backend (Workers):
+ - `JWT_SECRET`: Strong random secret for JWT signing
+ - `EMAIL_API_KEY`: Resend or SendGrid API key
+ - `AUTHORIZED_EMAILS`: Comma-separated list of authorized emails
+ - `FRONTEND_URL`: https://qrurl.us
+ - `BACKEND_URL`: https://qrurl.us
+
+ ### Frontend (Build-time):
+ - `VITE_API_URL`: https://api.qrurl.us/api
+ - `VITE_SHORT_URL`: https://qrurl.us
+
+ ## Post-Deployment Checklist
+
+ - [ ] Verify Workers deployment at https://api.qrurl.us/health
+ - [ ] Verify Pages deployment at https://qrurl.us
+ - [ ] Test authentication flow
+ - [ ] Test URL creation and redirection
+ - [ ] Test logo upload to R2
+ - [ ] Verify QR code generation with logos
+ - [ ] Check analytics tracking
+ - [ ] Test rate limiting
+
+ ## Monitoring
+
+ - **Workers Analytics**: Cloudflare Dashboard → Workers & Pages → qrurl → Analytics
+ - **Pages Analytics**: Cloudflare Dashboard → Workers & Pages → qrurl-frontend → Analytics
+ - **R2 Storage**: Cloudflare Dashboard → R2 → qrurl-storage
+ - **D1 Database**: Cloudflare Dashboard → D1 → qrurl-db
+
+ ## Rollback
+
+ If issues occur:
+
+ 1. **Workers**: Deploy previous version via dashboard or:
+ ```bash
+ npx wrangler rollback
+ ```
+
+ 2. **Pages**: Rollback via dashboard to previous deployment
+
+ ## Troubleshooting
+
+ ### CORS Issues
+ - Verify `FRONTEND_URL` is set correctly in Workers environment
+ - Check custom domain configuration
+
+ ### Database Issues
+ - Ensure D1 database ID matches in wrangler.toml
+ - Run migrations: `npm run db:init:remote`
+
+ ### R2 Issues
+ - Verify R2 bucket exists: `qrurl-storage`
+ - Check bucket permissions
+
+ ### Domain Issues
+ - Ensure DNS records are proxied through Cloudflare
+ - Wait for DNS propagation (up to 48 hours)
\ No newline at end of file
setup-secrets.sh +28 -0
@@ @@ -0,0 +1,28 @@
+ #!/bin/bash
+
+ # Production secrets setup script
+ # Run this once to configure production secrets
+
+ echo "Setting up Cloudflare Workers secrets for production..."
+
+ # Generate a strong JWT secret
+ JWT_SECRET=$(openssl rand -base64 32)
+ echo "Generated JWT_SECRET"
+
+ # Prompt for email API key
+ read -p "Enter your Email API Key (Resend/SendGrid): " EMAIL_API_KEY
+
+ # Prompt for authorized emails
+ read -p "Enter authorized emails (comma-separated): " AUTHORIZED_EMAILS
+
+ # Set the secrets
+ echo "$JWT_SECRET" | npx wrangler secret put JWT_SECRET
+ echo "$EMAIL_API_KEY" | npx wrangler secret put EMAIL_API_KEY
+ echo "$AUTHORIZED_EMAILS" | npx wrangler secret put AUTHORIZED_EMAILS
+
+ echo "✅ Secrets configured successfully!"
+ echo ""
+ echo "Next steps:"
+ echo "1. Add GitHub secrets (CLOUDFLARE_API_TOKEN and CLOUDFLARE_ACCOUNT_ID)"
+ echo "2. Configure custom domains in Cloudflare dashboard"
+ echo "3. Push to main branch to trigger deployment"
\ No newline at end of file
wrangler.production.toml +40 -0
@@ @@ -0,0 +1,40 @@
+ name = "qrurl"
+ main = "src/index.js"
+ compatibility_date = "2024-12-01"
+ compatibility_flags = ["nodejs_compat"]
+ account_id = "b253e6fbfd2f7757cadd0386de5bde3f"
+
+ # Custom domain
+ route = { pattern = "api.qrurl.us/*", custom_domain = true }
+
+ # D1 Database
+ [[d1_databases]]
+ binding = "DB"
+ database_name = "qrurl-db"
+ database_id = "17eb6fdb-19da-4ed7-931c-a4cdef281f8c"
+
+ # R2 Storage
+ [[r2_buckets]]
+ binding = "STORAGE"
+ bucket_name = "qrurl-storage"
+
+ # KV Namespace for caching
+ [[kv_namespaces]]
+ binding = "CACHE"
+ id = "1cacb0f1b44b4324b62c1bc010ff15f5"
+
+ # Environment Variables (set in Cloudflare dashboard or via secrets)
+ [vars]
+ FRONTEND_URL = "https://qrurl.us"
+ BACKEND_URL = "https://qrurl.us"
+
+ # Production settings
+ [env.production]
+ name = "qrurl-production"
+
+ # Rate limiting
+ [[unsafe.bindings]]
+ name = "RATE_LIMITER"
+ type = "ratelimit"
+ namespace_id = "1"
+ simple = { limit = 60, period = 60 }
\ No newline at end of file