Add comprehensive production deployment manual guide
This commit is contained in:
602
PRODUCTION_DEPLOYMENT.md
Normal file
602
PRODUCTION_DEPLOYMENT.md
Normal file
@@ -0,0 +1,602 @@
|
|||||||
|
# SmoothSchedule - Production Deployment Manual
|
||||||
|
|
||||||
|
Complete step-by-step guide for manually deploying SmoothSchedule from scratch on a production server. This guide is useful when you need to reset the entire production deployment or troubleshoot deployment issues.
|
||||||
|
|
||||||
|
## Table of Contents
|
||||||
|
|
||||||
|
1. [Prerequisites](#prerequisites)
|
||||||
|
2. [Complete Fresh Deployment](#complete-fresh-deployment)
|
||||||
|
3. [Docker Build & Startup](#docker-build--startup)
|
||||||
|
4. [Database Initialization](#database-initialization)
|
||||||
|
5. [Static Files & Migrations](#static-files--migrations)
|
||||||
|
6. [Verification Steps](#verification-steps)
|
||||||
|
7. [Troubleshooting](#troubleshooting)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
### Required on Production Server
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check these are installed and running
|
||||||
|
docker --version # Docker 20.10+
|
||||||
|
docker compose --version # Docker Compose 2.0+
|
||||||
|
```
|
||||||
|
|
||||||
|
### Required Locally (Before Deployment)
|
||||||
|
|
||||||
|
1. All code changes committed to git (`main` branch)
|
||||||
|
2. All missing files added to git and pushed
|
||||||
|
3. Production environment variables backed up locally
|
||||||
|
4. `.envs/.production/` directory exists with proper credentials
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Complete Fresh Deployment
|
||||||
|
|
||||||
|
### Step 1: Save Production Environment Variables Locally
|
||||||
|
|
||||||
|
**On your local development machine:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Backup current production environment variables
|
||||||
|
scp poduck@smoothschedule.com:~/smoothschedule/smoothschedule/.envs/.production/.django \
|
||||||
|
/tmp/production_django_env_backup
|
||||||
|
|
||||||
|
scp poduck@smoothschedule.com:~/smoothschedule/smoothschedule/.envs/.production/.postgres \
|
||||||
|
/tmp/production_postgres_env_backup
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 2: Prepare & Commit All Code Changes Locally
|
||||||
|
|
||||||
|
**On your local development machine:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/poduck/Desktop/smoothschedule2
|
||||||
|
|
||||||
|
# Check for any missing files
|
||||||
|
git status
|
||||||
|
|
||||||
|
# Add all changes and new files
|
||||||
|
git add -A
|
||||||
|
|
||||||
|
# Review staged changes
|
||||||
|
git diff --cached
|
||||||
|
|
||||||
|
# Commit changes
|
||||||
|
git commit -m "Production deployment: Add missing files and config updates"
|
||||||
|
|
||||||
|
# Push to main branch
|
||||||
|
git push origin main
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 3: Bring Down Production Containers
|
||||||
|
|
||||||
|
**SSH into production server:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ssh poduck@smoothschedule.com
|
||||||
|
|
||||||
|
cd ~/smoothschedule/smoothschedule
|
||||||
|
|
||||||
|
# Stop all containers (preserves volumes)
|
||||||
|
docker compose -f docker-compose.production.yml down
|
||||||
|
|
||||||
|
# Or to completely reset and remove volumes (careful!):
|
||||||
|
docker compose -f docker-compose.production.yml down -v
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 4: Remove Production Codebase
|
||||||
|
|
||||||
|
**On production server:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~
|
||||||
|
|
||||||
|
# Remove everything
|
||||||
|
rm -rf smoothschedule
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 5: Pull Fresh Code from Git
|
||||||
|
|
||||||
|
**On production server:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~
|
||||||
|
|
||||||
|
# Clone the repository
|
||||||
|
git clone https://git.talova.net/poduck/smoothschedule.git smoothschedule
|
||||||
|
|
||||||
|
cd smoothschedule
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note:** If git authentication fails, configure credentials on the server:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git config --global user.email "poduck@smoothschedule.com"
|
||||||
|
git config --global user.name "Poduck"
|
||||||
|
|
||||||
|
# Or store credentials
|
||||||
|
git credential approve
|
||||||
|
# Then paste: protocol=https
|
||||||
|
# host=git.talova.net
|
||||||
|
# username=poduck
|
||||||
|
# password=chaff/starry
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 6: Restore Production Environment Variables
|
||||||
|
|
||||||
|
**On production server:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/smoothschedule/smoothschedule
|
||||||
|
|
||||||
|
# Create the .envs/.production directory if it doesn't exist
|
||||||
|
mkdir -p .envs/.production
|
||||||
|
|
||||||
|
# Restore from backups on local machine or recreate them
|
||||||
|
# Option A: Use SCP to copy from local machine
|
||||||
|
scp /tmp/production_django_env_backup poduck@smoothschedule.com:~/smoothschedule/smoothschedule/.envs/.production/.django
|
||||||
|
scp /tmp/production_postgres_env_backup poduck@smoothschedule.com:~/smoothschedule/smoothschedule/.envs/.production/.postgres
|
||||||
|
|
||||||
|
# Option B: Manually recreate the files on the production server
|
||||||
|
# (see Environment Variables section below)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Docker Build & Startup
|
||||||
|
|
||||||
|
### Step 7: Build Docker Images
|
||||||
|
|
||||||
|
**On production server:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/smoothschedule/smoothschedule
|
||||||
|
|
||||||
|
# Build all production Docker images
|
||||||
|
docker compose -f docker-compose.production.yml build
|
||||||
|
```
|
||||||
|
|
||||||
|
**Expected output:**
|
||||||
|
```
|
||||||
|
✓ Successfully built:
|
||||||
|
- smoothschedule_production_django
|
||||||
|
- smoothschedule_production_celeryworker
|
||||||
|
- smoothschedule_production_celerybeat
|
||||||
|
- smoothschedule_production_flower
|
||||||
|
- smoothschedule_production_postgres
|
||||||
|
- smoothschedule_production_traefik
|
||||||
|
- smoothschedule-awscli
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 8: Start Containers
|
||||||
|
|
||||||
|
**On production server:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/smoothschedule/smoothschedule
|
||||||
|
|
||||||
|
# Start all containers in detached mode
|
||||||
|
docker compose -f docker-compose.production.yml up -d
|
||||||
|
|
||||||
|
# Wait for services to stabilize (10-15 seconds)
|
||||||
|
sleep 15
|
||||||
|
|
||||||
|
# Check container status
|
||||||
|
docker compose -f docker-compose.production.yml ps
|
||||||
|
```
|
||||||
|
|
||||||
|
**Expected status:** All containers should be `Up` or `Healthy`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Database Initialization
|
||||||
|
|
||||||
|
### Step 9: Run Database Migrations
|
||||||
|
|
||||||
|
**On production server:**
|
||||||
|
|
||||||
|
The application uses django-tenants for multi-tenant support. Migrations must be run in this order:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/smoothschedule/smoothschedule
|
||||||
|
|
||||||
|
# 1. Migrate the public/shared schema (all shared apps)
|
||||||
|
docker compose -f docker-compose.production.yml exec -T django \
|
||||||
|
python manage.py migrate_schemas --shared
|
||||||
|
|
||||||
|
# Expected output should show multiple migrations applied to "public" schema
|
||||||
|
```
|
||||||
|
|
||||||
|
**If you get "service django is not running":**
|
||||||
|
|
||||||
|
The Django container may not be fully started. Wait a bit longer:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sleep 30 # Wait for Django to initialize
|
||||||
|
docker compose -f docker-compose.production.yml exec -T django \
|
||||||
|
python manage.py migrate_schemas --shared
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Static Files & Migrations
|
||||||
|
|
||||||
|
### Step 10: Collect Static Files
|
||||||
|
|
||||||
|
**On production server:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/smoothschedule/smoothschedule
|
||||||
|
|
||||||
|
docker compose -f docker-compose.production.yml exec -T django \
|
||||||
|
python manage.py collectstatic --noinput
|
||||||
|
```
|
||||||
|
|
||||||
|
This collects all static files (CSS, JS, images) and uploads them to:
|
||||||
|
- **Local filesystem:** `smoothschedule/staticfiles/`
|
||||||
|
- **DigitalOcean Spaces/S3:** Configured via `DJANGO_AWS_*` environment variables
|
||||||
|
|
||||||
|
### Step 11: Create Superuser (First Time Only)
|
||||||
|
|
||||||
|
**On production server, if this is a fresh installation:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/smoothschedule/smoothschedule
|
||||||
|
|
||||||
|
docker compose -f docker-compose.production.yml exec django \
|
||||||
|
python manage.py createsuperuser
|
||||||
|
|
||||||
|
# Follow the prompts to create the admin user
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 12: Create Initial Tenant (First Time Only)
|
||||||
|
|
||||||
|
**On production server, if you need a demo tenant:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/smoothschedule/smoothschedule
|
||||||
|
|
||||||
|
docker compose -f docker-compose.production.yml exec django python manage.py shell
|
||||||
|
```
|
||||||
|
|
||||||
|
Then in the Django shell:
|
||||||
|
|
||||||
|
```python
|
||||||
|
from core.models import Tenant, Domain
|
||||||
|
from django.utils.text import slugify
|
||||||
|
|
||||||
|
# Create a tenant
|
||||||
|
tenant = Tenant.objects.create(
|
||||||
|
name="Demo Company",
|
||||||
|
slug="demo",
|
||||||
|
is_free_trial=False,
|
||||||
|
is_temporary=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Create a domain for the tenant
|
||||||
|
Domain.objects.create(
|
||||||
|
domain="demo.smoothschedule.com",
|
||||||
|
tenant=tenant,
|
||||||
|
)
|
||||||
|
|
||||||
|
print(f"Created tenant: {tenant.name} with domain: demo.smoothschedule.com")
|
||||||
|
exit()
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Verification Steps
|
||||||
|
|
||||||
|
### Step 13: Verify All Services Are Running
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/smoothschedule/smoothschedule
|
||||||
|
|
||||||
|
# Check container status
|
||||||
|
docker compose -f docker-compose.production.yml ps
|
||||||
|
|
||||||
|
# View logs for any errors
|
||||||
|
docker compose -f docker-compose.production.yml logs --tail=50
|
||||||
|
|
||||||
|
# Check specific service logs
|
||||||
|
docker compose -f docker-compose.production.yml logs django --tail=30
|
||||||
|
docker compose -f docker-compose.production.yml logs postgres --tail=30
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 14: Test API Endpoints
|
||||||
|
|
||||||
|
**From your local machine:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Test the backend API
|
||||||
|
curl -s "https://smoothschedule.com/api/health/" | jq
|
||||||
|
|
||||||
|
# Test tenant access
|
||||||
|
curl -s "https://demo.smoothschedule.com/api/resources/" | jq
|
||||||
|
|
||||||
|
# Test platform admin
|
||||||
|
curl -s "https://platform.smoothschedule.com/api/admin/businesses/" | jq
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 15: Verify Nginx Frontend
|
||||||
|
|
||||||
|
The frontend should be accessible at:
|
||||||
|
- **Main site:** `https://smoothschedule.com`
|
||||||
|
- **Platform dashboard:** `https://platform.smoothschedule.com`
|
||||||
|
- **Tenant subdomain:** `https://demo.smoothschedule.com`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Environment Variables Reference
|
||||||
|
|
||||||
|
### Django Configuration (`.envs/.production/.django`)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Security & Secrets
|
||||||
|
DJANGO_SECRET_KEY=your-secret-key-here
|
||||||
|
DJANGO_DEBUG=False
|
||||||
|
DJANGO_ALLOWED_HOSTS=smoothschedule.com,platform.smoothschedule.com,*.smoothschedule.com
|
||||||
|
|
||||||
|
# Admin & URLs
|
||||||
|
DJANGO_ADMIN_URL=<random-slug>/
|
||||||
|
FRONTEND_URL=https://platform.smoothschedule.com
|
||||||
|
PLATFORM_BASE_URL=https://platform.smoothschedule.com
|
||||||
|
|
||||||
|
# Celery & Redis
|
||||||
|
REDIS_URL=redis://redis:6379/0
|
||||||
|
CELERY_BROKER_URL=redis://redis:6379/0
|
||||||
|
|
||||||
|
# AWS/DigitalOcean Spaces (for media storage)
|
||||||
|
DJANGO_AWS_ACCESS_KEY_ID=your-access-key
|
||||||
|
DJANGO_AWS_SECRET_ACCESS_KEY=your-secret-key
|
||||||
|
DJANGO_AWS_STORAGE_BUCKET_NAME=smoothschedule
|
||||||
|
DJANGO_AWS_S3_ENDPOINT_URL=https://nyc3.digitaloceanspaces.com
|
||||||
|
DJANGO_AWS_S3_REGION_NAME=nyc3
|
||||||
|
DJANGO_AWS_S3_CUSTOM_DOMAIN=smoothschedule.nyc3.digitaloceanspaces.com
|
||||||
|
|
||||||
|
# Email Configuration (optional)
|
||||||
|
MAILGUN_API_KEY=your-mailgun-key
|
||||||
|
MAILGUN_DOMAIN=mg.smoothschedule.com
|
||||||
|
|
||||||
|
# SSL/Security
|
||||||
|
DJANGO_SECURE_SSL_REDIRECT=True
|
||||||
|
DJANGO_SECURE_HSTS_SECONDS=60
|
||||||
|
DJANGO_SECURE_HSTS_INCLUDE_SUBDOMAINS=True
|
||||||
|
DJANGO_SECURE_HSTS_PRELOAD=True
|
||||||
|
DJANGO_SESSION_COOKIE_SECURE=True
|
||||||
|
DJANGO_CSRF_COOKIE_SECURE=True
|
||||||
|
|
||||||
|
# Sentry (optional - error tracking)
|
||||||
|
SENTRY_DSN=
|
||||||
|
SENTRY_ENVIRONMENT=production
|
||||||
|
SENTRY_TRACES_SAMPLE_RATE=0.1
|
||||||
|
```
|
||||||
|
|
||||||
|
### PostgreSQL Configuration (`.envs/.production/.postgres`)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
POSTGRES_HOST=postgres
|
||||||
|
POSTGRES_PORT=5432
|
||||||
|
POSTGRES_DB=smoothschedule
|
||||||
|
POSTGRES_USER=<random-username>
|
||||||
|
POSTGRES_PASSWORD=<random-secure-password>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Django Container Won't Start
|
||||||
|
|
||||||
|
**Symptom:** `docker compose ps` shows Django as exited
|
||||||
|
|
||||||
|
**Solution:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/smoothschedule/smoothschedule
|
||||||
|
|
||||||
|
# View full error logs
|
||||||
|
docker compose -f docker-compose.production.yml logs django --tail=100
|
||||||
|
|
||||||
|
# Check if database is accessible
|
||||||
|
docker compose -f docker-compose.production.yml logs postgres --tail=20
|
||||||
|
|
||||||
|
# Restart Django after fixing the issue
|
||||||
|
docker compose -f docker-compose.production.yml restart django
|
||||||
|
```
|
||||||
|
|
||||||
|
### Migration Fails with "role does not exist"
|
||||||
|
|
||||||
|
**Symptom:** Error when running `migrate_schemas --shared`:
|
||||||
|
```
|
||||||
|
FATAL: role "postgres" does not exist
|
||||||
|
```
|
||||||
|
|
||||||
|
**Solution:** The database volume is corrupted. Reset and restart:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/smoothschedule/smoothschedule
|
||||||
|
|
||||||
|
# Stop and remove all volumes
|
||||||
|
docker compose -f docker-compose.production.yml down -v
|
||||||
|
|
||||||
|
# Restart (this will recreate the database)
|
||||||
|
docker compose -f docker-compose.production.yml up -d
|
||||||
|
|
||||||
|
# Wait for database to initialize (30 seconds)
|
||||||
|
sleep 30
|
||||||
|
|
||||||
|
# Try migrations again
|
||||||
|
docker compose -f docker-compose.production.yml exec -T django \
|
||||||
|
python manage.py migrate_schemas --shared
|
||||||
|
```
|
||||||
|
|
||||||
|
### Cannot Connect to Production Server
|
||||||
|
|
||||||
|
**Check SSH access:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ssh poduck@smoothschedule.com "echo 'Connection successful'"
|
||||||
|
```
|
||||||
|
|
||||||
|
**If that fails:**
|
||||||
|
- Verify your SSH key is authorized on the server
|
||||||
|
- Check firewall rules allow SSH (port 22)
|
||||||
|
- Verify DNS resolves `smoothschedule.com` to the correct IP
|
||||||
|
|
||||||
|
### Traefik Certificate Issues
|
||||||
|
|
||||||
|
**Symptom:** SSL certificate errors, HTTP redirects failing
|
||||||
|
|
||||||
|
**Solution:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/smoothschedule/smoothschedule
|
||||||
|
|
||||||
|
# Check Traefik logs
|
||||||
|
docker compose -f docker-compose.production.yml logs traefik --tail=50
|
||||||
|
|
||||||
|
# Restart Traefik to request new certificates
|
||||||
|
docker compose -f docker-compose.production.yml restart traefik
|
||||||
|
|
||||||
|
# Wait for Let's Encrypt to issue certificates (5-10 minutes)
|
||||||
|
# Check via: https://smoothschedule.com (should show valid cert)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Frontend Not Loading
|
||||||
|
|
||||||
|
**Verify nginx container is running:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check if nginx image was built
|
||||||
|
docker images | grep smoothschedule
|
||||||
|
|
||||||
|
# If missing, rebuild
|
||||||
|
docker compose -f docker-compose.production.yml build nginx
|
||||||
|
|
||||||
|
# Restart the service
|
||||||
|
docker compose -f docker-compose.production.yml restart
|
||||||
|
|
||||||
|
# Check logs
|
||||||
|
docker logs $(docker ps -q --filter "name=nginx")
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Quick Reference Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# SSH to production server
|
||||||
|
ssh poduck@smoothschedule.com
|
||||||
|
|
||||||
|
# Navigate to project
|
||||||
|
cd ~/smoothschedule/smoothschedule
|
||||||
|
|
||||||
|
# View all container logs
|
||||||
|
docker compose -f docker-compose.production.yml logs -f
|
||||||
|
|
||||||
|
# View Django logs only
|
||||||
|
docker compose -f docker-compose.production.yml logs django -f --tail=100
|
||||||
|
|
||||||
|
# Stop all containers
|
||||||
|
docker compose -f docker-compose.production.yml down
|
||||||
|
|
||||||
|
# Start all containers
|
||||||
|
docker compose -f docker-compose.production.yml up -d
|
||||||
|
|
||||||
|
# Restart a specific service
|
||||||
|
docker compose -f docker-compose.production.yml restart django
|
||||||
|
|
||||||
|
# Run a Django management command
|
||||||
|
docker compose -f docker-compose.production.yml exec -T django python manage.py <command>
|
||||||
|
|
||||||
|
# Access Django shell
|
||||||
|
docker compose -f docker-compose.production.yml exec django python manage.py shell
|
||||||
|
|
||||||
|
# Create a database backup
|
||||||
|
docker compose -f docker-compose.production.yml exec -T postgres \
|
||||||
|
pg_dump -U $POSTGRES_USER smoothschedule > backup.sql
|
||||||
|
|
||||||
|
# Execute arbitrary SQL
|
||||||
|
docker compose -f docker-compose.production.yml exec -T postgres \
|
||||||
|
psql -U $POSTGRES_USER smoothschedule -c "SELECT version();"
|
||||||
|
|
||||||
|
# Check Docker resource usage
|
||||||
|
docker stats
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Advanced: Rollback Procedure
|
||||||
|
|
||||||
|
If a deployment fails catastrophically:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Stop everything
|
||||||
|
cd ~/smoothschedule/smoothschedule
|
||||||
|
docker compose -f docker-compose.production.yml down
|
||||||
|
|
||||||
|
# 2. Restore from database backup (if available)
|
||||||
|
docker compose -f docker-compose.production.yml exec -T postgres \
|
||||||
|
psql -U $POSTGRES_USER smoothschedule < backup.sql
|
||||||
|
|
||||||
|
# 3. Checkout previous git commit
|
||||||
|
cd ~/smoothschedule
|
||||||
|
git checkout <previous-commit-hash>
|
||||||
|
|
||||||
|
# 4. Rebuild and restart
|
||||||
|
cd smoothschedule
|
||||||
|
docker compose -f docker-compose.production.yml build
|
||||||
|
docker compose -f docker-compose.production.yml up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Monitoring Checklist
|
||||||
|
|
||||||
|
After deployment, monitor these for 24 hours:
|
||||||
|
|
||||||
|
- [ ] No error logs in `docker compose logs django`
|
||||||
|
- [ ] API endpoints respond with 200 status
|
||||||
|
- [ ] SSL certificates are valid (https://smoothschedule.com)
|
||||||
|
- [ ] Frontend loads without console errors
|
||||||
|
- [ ] Tenant subdomains work correctly
|
||||||
|
- [ ] Static files are being served (CSS, JS load)
|
||||||
|
- [ ] Background tasks execute (check Celery worker logs)
|
||||||
|
- [ ] No database connection errors
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Important Notes
|
||||||
|
|
||||||
|
1. **Always backup before major changes:**
|
||||||
|
- Database: `pg_dump`
|
||||||
|
- Environment variables: Copy `.envs/.production/` locally
|
||||||
|
- Code: Git commits
|
||||||
|
|
||||||
|
2. **Never modify code on production directly:**
|
||||||
|
- Change code locally → Git push → Production git pull
|
||||||
|
- Only edit `.env` files directly on production
|
||||||
|
|
||||||
|
3. **Multi-Tenancy Considerations:**
|
||||||
|
- Each tenant gets a separate PostgreSQL schema
|
||||||
|
- Migrations apply to "public" schema (shared) first
|
||||||
|
- Tenant migrations happen automatically on first request to new tenant
|
||||||
|
|
||||||
|
4. **Docker Compose File:**
|
||||||
|
- Always use `-f docker-compose.production.yml` for production
|
||||||
|
- Never use `-f docker-compose.local.yml` on production
|
||||||
|
|
||||||
|
5. **Persistence:**
|
||||||
|
- Database: `production_postgres_data` volume
|
||||||
|
- Redis: `production_redis_data` volume
|
||||||
|
- Traefik certs: `production_traefik` volume
|
||||||
|
- These are preserved when using `down` (not `down -v`)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Last Updated:** December 2025
|
||||||
|
**Deployment Version:** Manual v1.0
|
||||||
Reference in New Issue
Block a user