Files
smoothschedule/DEPLOYMENT.md
poduck f8d8419622 Improve deployment process and add login redirect logic
Deployment improvements:
- Add template env files (.envs.example/) for documentation
- Create init-production.sh for one-time server setup
- Create build-activepieces.sh for building/deploying AP image
- Update deploy.sh with --deploy-ap flag
- Make custom-pieces-metadata.sql idempotent
- Update DEPLOYMENT.md with comprehensive instructions

Frontend:
- Redirect logged-in business owners from root domain to tenant dashboard
- Redirect logged-in users from /login to /dashboard on their tenant
- Log out customers on wrong subdomain instead of redirecting

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 23:13:56 -05:00

438 lines
12 KiB
Markdown

# SmoothSchedule Production Deployment Guide
This guide covers deploying SmoothSchedule to a production server.
## Table of Contents
1. [Prerequisites](#prerequisites)
2. [Quick Reference](#quick-reference)
3. [Initial Server Setup](#initial-server-setup-first-time-only)
4. [Regular Deployments](#regular-deployments)
5. [Activepieces Updates](#activepieces-updates)
6. [Troubleshooting](#troubleshooting)
7. [Maintenance](#maintenance)
## Prerequisites
### Server Requirements
- Ubuntu 20.04+ or Debian 11+
- 4GB RAM minimum (2GB works but cannot build Activepieces image)
- 40GB disk space
- Docker and Docker Compose v2 installed
- Domain with wildcard DNS configured
### Local Requirements (for deployment)
- Git access to the repository
- SSH access to the production server
- Docker (for building Activepieces image)
### Required Accounts/Services
- DigitalOcean Spaces (for static/media files)
- Stripe (for payments)
- Twilio (for SMS/phone features)
- OpenAI API (optional, for Activepieces AI copilot)
## Quick Reference
```bash
# Regular deployment (after initial setup)
./deploy.sh
# Deploy with Activepieces image rebuild
./deploy.sh --deploy-ap
# Deploy specific services only
./deploy.sh django nginx
# Skip migrations (config changes only)
./deploy.sh --no-migrate
```
## Initial Server Setup (First Time Only)
### 1. Server Preparation
```bash
# SSH into production server
ssh your-user@your-server
# Install Docker (if not already installed)
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
sudo usermod -aG docker $USER
# Logout and login again for group changes
exit
ssh your-user@your-server
```
### 2. Clone Repository
```bash
git clone https://your-repo-url ~/smoothschedule
cd ~/smoothschedule/smoothschedule
```
### 3. Create Environment Files
Copy the template files and fill in your values:
```bash
mkdir -p .envs/.production
cp .envs.example/.django .envs/.production/.django
cp .envs.example/.postgres .envs/.production/.postgres
cp .envs.example/.activepieces .envs/.production/.activepieces
```
Edit each file with your production values:
```bash
nano .envs/.production/.django
nano .envs/.production/.postgres
nano .envs/.production/.activepieces
```
**Key values to configure:**
| File | Variable | Description |
|------|----------|-------------|
| `.django` | `DJANGO_SECRET_KEY` | Generate: `openssl rand -hex 32` |
| `.django` | `DJANGO_ALLOWED_HOSTS` | `.yourdomain.com` |
| `.django` | `STRIPE_*` | Your Stripe keys (live keys for production) |
| `.django` | `TWILIO_*` | Your Twilio credentials |
| `.django` | `AWS_*` | DigitalOcean Spaces credentials |
| `.postgres` | `POSTGRES_USER` | Generate random username |
| `.postgres` | `POSTGRES_PASSWORD` | Generate: `openssl rand -hex 32` |
| `.activepieces` | `AP_JWT_SECRET` | Generate: `openssl rand -hex 32` |
| `.activepieces` | `AP_ENCRYPTION_KEY` | Generate: `openssl rand -hex 16` |
| `.activepieces` | `AP_POSTGRES_USERNAME` | Generate random username |
| `.activepieces` | `AP_POSTGRES_PASSWORD` | Generate: `openssl rand -hex 32` |
**Important:** `AP_JWT_SECRET` must be copied to `.django` as well!
### 4. DNS Configuration
Configure these DNS records:
```
Type Name Value TTL
A yourdomain.com YOUR_SERVER_IP 300
A *.yourdomain.com YOUR_SERVER_IP 300
CNAME www yourdomain.com 300
```
### 5. Build Activepieces Image (on your local machine)
The production server typically cannot build this image (requires 4GB+ RAM):
```bash
# On your LOCAL machine, not the server
cd ~/smoothschedule
./scripts/build-activepieces.sh deploy
```
Or manually:
```bash
cd activepieces-fork
docker build -t smoothschedule_production_activepieces .
docker save smoothschedule_production_activepieces | gzip > /tmp/ap.tar.gz
scp /tmp/ap.tar.gz your-user@your-server:/tmp/
ssh your-user@your-server 'gunzip -c /tmp/ap.tar.gz | docker load'
```
### 6. Run Initialization Script
```bash
# On the server
cd ~/smoothschedule/smoothschedule
chmod +x scripts/init-production.sh
./scripts/init-production.sh
```
This script will:
1. Verify environment files
2. Generate any missing security keys
3. Start PostgreSQL and Redis
4. Create the Activepieces database
5. Start all services
6. Run Django migrations
7. Guide you through Activepieces platform setup
### 7. Complete Activepieces Platform Setup
After the init script completes:
1. Visit `https://automations.yourdomain.com`
2. Create an admin account (this creates the platform)
3. Get the platform ID:
```bash
docker compose -f docker-compose.production.yml exec postgres \
psql -U <ap_db_user> -d activepieces -c "SELECT id FROM platform"
```
4. Update `AP_PLATFORM_ID` in both:
- `.envs/.production/.activepieces`
- `.envs/.production/.django`
5. Restart services:
```bash
docker compose -f docker-compose.production.yml restart
```
### 8. Create First Tenant
```bash
docker compose -f docker-compose.production.yml exec django python manage.py shell
```
```python
from smoothschedule.identity.core.models import Tenant, Domain
# Create tenant
tenant = Tenant.objects.create(
name="Demo Business",
subdomain="demo",
schema_name="demo"
)
# Create domain
Domain.objects.create(
tenant=tenant,
domain="demo.yourdomain.com",
is_primary=True
)
```
### 9. Provision Activepieces Connection
```bash
docker compose -f docker-compose.production.yml exec django \
python manage.py provision_ap_connections --tenant demo
```
### 10. Verify Deployment
```bash
# Check all containers are running
docker compose -f docker-compose.production.yml ps
# Test endpoints
curl https://yourdomain.com/api/
curl https://platform.yourdomain.com/
curl https://automations.yourdomain.com/api/v1/health
```
## Regular Deployments
After initial setup, deployments are simple:
```bash
# From your local machine
cd ~/smoothschedule
# Commit and push your changes
git add .
git commit -m "Your changes"
git push
# Deploy
./deploy.sh
```
### Deployment Options
| Command | Description |
|---------|-------------|
| `./deploy.sh` | Full deployment with migrations |
| `./deploy.sh --no-migrate` | Deploy without running migrations |
| `./deploy.sh --deploy-ap` | Rebuild and deploy Activepieces image |
| `./deploy.sh django` | Rebuild only Django container |
| `./deploy.sh nginx traefik` | Rebuild specific services |
### What the Deploy Script Does
1. Checks for uncommitted changes
2. Verifies changes are pushed to remote
3. (If `--deploy-ap`) Builds and transfers Activepieces image
4. SSHs to server and pulls latest code
5. Backs up and restores `.envs` directory
6. Builds Docker images
7. Starts containers
8. Sets up Activepieces database (if needed)
9. Runs Django migrations (unless `--no-migrate`)
10. Seeds platform plugins for all tenants
## Activepieces Updates
When you modify custom pieces (in `activepieces-fork/`):
1. Make your changes to piece code
2. Commit and push
3. Deploy with the image flag:
```bash
./deploy.sh --deploy-ap
```
The Activepieces container will:
1. Start with the new image
2. Run `publish-pieces.sh` to register custom pieces
3. Insert piece metadata into the database
### Custom Pieces
Custom pieces are located in:
- `activepieces-fork/packages/pieces/community/smoothschedule/` - Main SmoothSchedule piece
- `activepieces-fork/packages/pieces/community/python-code/` - Python code execution
- `activepieces-fork/packages/pieces/community/ruby-code/` - Ruby code execution
Piece metadata is registered via:
- `activepieces-fork/custom-pieces-metadata.sql` - Database registration
- `activepieces-fork/publish-pieces.sh` - Container startup script
## Troubleshooting
### View Logs
```bash
# All services
docker compose -f docker-compose.production.yml logs -f
# Specific service
docker compose -f docker-compose.production.yml logs -f django
docker compose -f docker-compose.production.yml logs -f activepieces
docker compose -f docker-compose.production.yml logs -f traefik
```
### Restart Services
```bash
# All services
docker compose -f docker-compose.production.yml restart
# Specific service
docker compose -f docker-compose.production.yml restart django
docker compose -f docker-compose.production.yml restart activepieces
```
### Django Shell
```bash
docker compose -f docker-compose.production.yml exec django python manage.py shell
```
### Database Access
```bash
# SmoothSchedule database
docker compose -f docker-compose.production.yml exec postgres \
psql -U <postgres_user> -d smoothschedule
# Activepieces database
docker compose -f docker-compose.production.yml exec postgres \
psql -U <ap_user> -d activepieces
```
### Common Issues
**1. Activepieces pieces not showing up**
```bash
# Check if platform exists
docker compose -f docker-compose.production.yml exec postgres \
psql -U <ap_user> -d activepieces -c "SELECT id FROM platform"
# Restart to re-run piece registration
docker compose -f docker-compose.production.yml restart activepieces
# Check logs for errors
docker compose -f docker-compose.production.yml logs activepieces | grep -i error
```
**2. 502 Bad Gateway**
- Service is still starting, wait a moment
- Check container health: `docker compose ps`
- Check logs for errors
**3. Database connection errors**
- Verify credentials in `.envs/.production/`
- Ensure PostgreSQL is running: `docker compose ps postgres`
**4. Activepieces embedding not working**
- Verify `AP_JWT_SECRET` matches in both `.django` and `.activepieces`
- Verify `AP_PLATFORM_ID` is set correctly in both files
- Check `AP_EMBEDDING_ENABLED=true` in `.activepieces`
**5. SSL certificate issues**
```bash
# Check Traefik logs
docker compose -f docker-compose.production.yml logs traefik
# Verify DNS is pointing to server
dig yourdomain.com +short
# Ensure ports 80 and 443 are open
sudo ufw allow 80
sudo ufw allow 443
```
## Maintenance
### Backups
```bash
# Database backup
docker compose -f docker-compose.production.yml exec postgres backup
# List backups
docker compose -f docker-compose.production.yml exec postgres backups
# Restore from backup
docker compose -f docker-compose.production.yml exec postgres restore backup_filename.sql.gz
```
### Monitoring
- **Flower Dashboard**: `https://yourdomain.com:5555` - Celery task monitoring
- **Container Status**: `docker compose ps`
- **Resource Usage**: `docker stats`
### Security Checklist
- [x] SSL/HTTPS enabled via Let's Encrypt (automatic with Traefik)
- [x] All secret keys are unique random values
- [x] Database passwords are strong
- [x] Flower dashboard is password protected
- [ ] Firewall configured (UFW)
- [ ] SSH key-based authentication only
- [ ] Regular backups configured
- [ ] Monitoring/alerting set up
## File Structure
```
smoothschedule/
├── deploy.sh # Main deployment script
├── DEPLOYMENT.md # This file
├── scripts/
│ └── build-activepieces.sh # Activepieces image builder
├── smoothschedule/
│ ├── docker-compose.production.yml
│ ├── scripts/
│ │ └── init-production.sh # One-time initialization
│ ├── .envs/
│ │ └── .production/ # Production secrets (NOT in git)
│ │ ├── .django
│ │ ├── .postgres
│ │ └── .activepieces
│ └── .envs.example/ # Template files (in git)
│ ├── .django
│ ├── .postgres
│ └── .activepieces
└── activepieces-fork/
├── Dockerfile
├── custom-pieces-metadata.sql
├── publish-pieces.sh
└── packages/pieces/community/
├── smoothschedule/ # Main custom piece
├── python-code/
└── ruby-code/
```