Appearance
Environment Management
This document covers environment URLs, infrastructure details, configurations, and management practices.
Environment URLs
Development
- Branch:
develop - Web App: https://dev-app.jubiloop.ca
- API: https://dev-api.jubiloop.ca
- Marketing: https://dev.jubiloop.ca
- Infrastructure: Shared droplet with QA
QA
- Branch:
qa - Web App: https://qa-app.jubiloop.ca
- API: https://qa-api.jubiloop.ca
- Marketing: https://qa.jubiloop.ca
- Infrastructure: Shared droplet with Dev
Production
- Branch:
main - Web App: https://app.jubiloop.ca (Protected with Zero Trust temporarily)
- API: https://api.jubiloop.ca
- Marketing: https://jubiloop.ca (Public)
- Marketing (www): https://www.jubiloop.ca (Public)
- Infrastructure: Dedicated droplet
Infrastructure Costs
Monthly Breakdown
- DigitalOcean Droplets: $24 total
- Dev/QA shared: $6/month (s-1vcpu-1gb)
- Production: $6/month (s-1vcpu-1gb)
- Neon Database: $0 (free tier - 0.5GB)
- Cloudflare: $0 (free tier)
- Domains: ~$2/month
- Total: ~$26/month
Droplet Specifications
- Size: 1 vCPU, 2GB RAM, 50GB SSD
- OS: Ubuntu 22.04 LTS
- Region: Toronto (tor1)
Service Locations
Backend (DigitalOcean)
- AdonisJS API
- Redis cache
- PostgreSQL (dev/qa only - local container)
- Caddy proxy
Frontend (Cloudflare Pages)
- React web app
- Next.js marketing site
Database
Development/QA
- Local PostgreSQL container
- Separate databases per environment
Production (Neon)
- Managed PostgreSQL service
- Automatic backups
- Connection pooling
- Free tier (0.5GB storage)
Environment Variables
All environment configuration is managed through env.deploy.yml:
yaml
# Common pattern for all environments
{ ENV }:
server:
PORT: 3333
DATABASE_URL: from_secrets # Becomes {ENV}_SERVER_DATABASE_URL
NODE_ENV: '{environment}'
webapp:
API_URL: 'https://{env}-api.jubiloop.ca'Environment-Specific Settings
Development:
- Debug logging enabled
- Relaxed rate limits (1000/hour)
- CORS allows localhost
- Verbose error messages
QA:
- Production-like settings
- Standard rate limits (500/hour)
- CORS restricted to QA domains
- Structured error logging
Production:
- Minimal logging
- Strict rate limits (100/hour)
- CORS limited to production domains
- Generic error messages
- Neon PostgreSQL connection string
- Backups enabled on droplet
External Service Configuration
Payment Processing (Stripe)
| Environment | Mode | Webhook Endpoint |
|---|---|---|
| Development | Test mode | dev-api.jubiloop.ca/webhooks/stripe |
| QA | Test mode | qa-api.jubiloop.ca/webhooks/stripe |
| Production | Live mode | api.jubiloop.ca/webhooks/stripe |
Email Service
The platform uses a comprehensive Email Infrastructure with:
| Environment | Resend (Transactional) | Brevo (Marketing) |
|---|---|---|
| Development | Sandbox mode | Test lists |
| QA | Limited sending | Sandbox campaigns |
| Production | Full sending | Live campaigns |
File Storage (Cloudflare R2)
| Environment | Bucket | Access |
|---|---|---|
| Development | jubiloop-dev | Public read for testing |
| QA | jubiloop-qa | Restricted access |
| Production | jubiloop-prod | Signed URLs only |
Database Management
Development & QA
- Shared PostgreSQL container on same droplet
- Separate databases:
jubiloop_devandjubiloop_qa - Can be reset anytime
- Test data seeding scripts available
Production
- Neon managed PostgreSQL
- Automated daily backups
- Point-in-time recovery
- Connection pooling via pgBouncer
Environment Promotion
Development → QA
- Code Freeze: Feature complete on
develop - Create PR: From
developtoqa - Automated Checks:
- Tests must pass
- Linting must pass
- Build must succeed
- Manual Review: Code review required
- Merge: Triggers automatic deployment
QA → Production
- QA Sign-off: All test cases passed
- Create PR: From
qatomain - Final Checks:
- No critical bugs
- Performance acceptable
- Security scan passed
- Approval: Requires admin approval
- Deploy: Merge triggers deployment
- Verify: Post-deployment checks
Rollback Procedures
Quick Rollback (< 5 minutes)
bash
# Via GitHub Actions
# 1. Go to Actions tab
# 2. Select "Deploy" workflow
# 3. Click "Run workflow"
# 4. Select previous commit SHADatabase Rollback
For database changes:
- Migrations are reversible
- Run rollback migration
- Deploy previous code version
Environment Isolation
Network Level
- No cross-environment communication
- Separate Redis instances
- Independent service deployments
Data Level
- No production data in dev/QA
- Separate secret keys
- Different API credentials
Access Control
- Production app requires Zero Trust auth (temporary)
- Production marketing site is public
- QA requires Zero Trust auth for all frontend apps
- Dev requires Zero Trust auth for all frontend apps
- API endpoints protected by session auth (not Zero Trust)
Monitoring by Environment
Development
- Basic health checks
- Docker logs
- Local debugging tools
QA
- Uptime monitoring
- Performance metrics
- Error tracking (when Sentry added)
Production
- 24/7 uptime monitoring
- Real-time alerts
- Performance tracking
- Error tracking with Sentry (planned)
Common Tasks
Refresh Dev/QA Database
bash
# SSH to dev-qa server
ssh deploy@dev-qa.jubiloop.ca
# Backup current data (optional)
docker exec postgres pg_dump jubiloop_dev > backup.sql
# Reset database
docker exec postgres psql -c "DROP DATABASE jubiloop_dev;"
docker exec postgres psql -c "CREATE DATABASE jubiloop_dev;"
# Run migrations
docker exec server npm run migration:runCheck Environment Health
bash
# Check all services
curl https://dev-api.jubiloop.ca/health
curl https://qa-api.jubiloop.ca/health
curl https://api.jubiloop.ca/healthView Logs
bash
# Development/QA
ssh deploy@dev-qa.jubiloop.ca
docker logs server-dev -f
docker logs server-qa -f
# Production
ssh deploy@<production-ip> # Get IP from terraform output
docker logs server -fTroubleshooting
Environment Not Deploying
- Check GitHub Actions for errors
- Verify branch protection rules
- Check secrets are set correctly
- Ensure Docker registry is accessible
Wrong Environment Variables
- Check
env.deploy.ymlis correct - Run
npm run generate:envlocally - Verify GitHub Secrets match
- Restart containers after changes
Database Connection Issues
- Check DATABASE_URL is correct
- Verify firewall rules
- Check connection pool limits
- Review PostgreSQL logs