Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 60 additions & 7 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -233,13 +233,66 @@ CHATWOOT_ADMIN_PASSWORD=CHANGE_ME_TO_A_SECURE_PASSWORD_MIN_32_CHARS
# ----------------------------------------------------------------------------
# Evolution API Configuration
# ----------------------------------------------------------------------------
# WhatsApp Business API gateway configuration

# Evolution API authentication
EVOLUTION_API_KEY=CHANGE_ME_TO_A_SECURE_API_KEY

# Evolution API encryption key
EVOLUTION_ENCRYPTION_KEY=CHANGE_ME_TO_A_64_CHARACTER_HEX_STRING
# WhatsApp Business API gateway for multi-instance WhatsApp connectivity
#
# Evolution API is a self-hosted WhatsApp Business API gateway that enables
# WhatsApp message sending/receiving through HTTP API endpoints and webhooks.
#
# Key Features:
# - Multi-instance support (multiple WhatsApp business accounts per server)
# - QR code authentication (scan with WhatsApp to connect)
# - Webhook delivery to n8n for incoming message events
# - PostgreSQL storage for message history and instance data
# - Redis caching for session management
#
# Security Architecture:
# - API key authentication required for all API operations
# - Instance-level authentication for granular access control
# - Database isolation (evolution_user has access only to evolution_db)
# - Network isolation (no port exposure, HTTPS via Caddy only)
#
# Integration Pattern:
# WhatsApp → Evolution API → Webhook → n8n → Chatwoot/other services
#
# ⚠️ CRITICAL SECURITY WARNINGS:
# 1. EVOLUTION_API_KEY: Protects ALL Evolution API operations (instance creation, message sending)
# - Use strong 32+ character key (generate with: openssl rand -base64 32)
# - Include in apikey header for ALL API requests
# - NEVER expose in client-side code or public repositories
# - Rotate regularly (monthly recommended for production)
#
# 2. EVOLUTION_DB_PASSWORD: PostgreSQL database access for message history
# - Already configured above in PostgreSQL section (line 48)
# - Used by Evolution API to store WhatsApp messages and instance configurations
#
# 3. EVOLUTION_WEBHOOK_URL: Destination for incoming WhatsApp messages
# - Must use HTTPS (HTTP webhooks will be rejected by Evolution API)
# - n8n webhook endpoint must be active before Evolution API sends events

# Evolution API hostname (subdomain for Evolution API service)
# Admin UI accessible at: https://${EVOLUTION_HOST}/manager
# API documentation: https://${EVOLUTION_HOST}/docs
EVOLUTION_HOST=evolution.${DOMAIN}

# Evolution API global authentication key
# Required in "apikey" header for ALL API operations:
# - Instance creation (POST /instance/create)
# - Message sending (POST /message/sendText/{instanceName})
# - Instance management (GET/DELETE /instance/{instanceName})
# Generate with: openssl rand -base64 32
# ⚠️ WARNING: Treat this key like a root password - it controls ALL WhatsApp instances
EVOLUTION_API_KEY=CHANGE_ME_TO_A_SECURE_API_KEY_MIN_32_CHARS

# Evolution API webhook URL for incoming WhatsApp messages
# Evolution API sends incoming messages to this n8n webhook endpoint
# n8n workflow receives messages and routes to Chatwoot or other services
# Format: https://{N8N_HOST}/webhook/{path}
# Must be HTTPS (Evolution API rejects HTTP webhooks for security)
EVOLUTION_WEBHOOK_URL=https://${N8N_HOST}/webhook/whatsapp-incoming

# Prisma database client identifier (internal - do not change)
# Used by Evolution API's Prisma ORM for connection pool naming
DATABASE_CONNECTION_CLIENT_NAME=evolution_api

# ----------------------------------------------------------------------------
# Directus Configuration
Expand Down
215 changes: 215 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,17 @@ jobs:
DIRECTUS_DB_PASSWORD=test_directus_password_12345678
EVOLUTION_DB_PASSWORD=test_evolution_password_12345678
REDIS_PASSWORD=test_redis_password_12345678901234567890
MONGODB_ROOT_PASSWORD=test_mongodb_root_password_12345678
LOWCODER_DB_PASSWORD=test_lowcoder_password_12345678901234567890
DOMAIN=example.com.br
EMAIL=admin@example.com.br
CORS_ALLOWED_ORIGINS=*
N8N_BASIC_AUTH_USER=admin
N8N_BASIC_AUTH_PASSWORD=test_n8n_auth_password_12345678
N8N_ENCRYPTION_KEY=test_n8n_encryption_key_12345678901234567890
EVOLUTION_API_KEY=test_evolution_api_key_12345678901234567890
EVOLUTION_HOST=evolution.example.com.br
EVOLUTION_WEBHOOK_URL=https://n8n.example.com.br/webhook/evolution
EOF

- name: Verify Redis configuration in docker-compose.yml
Expand Down Expand Up @@ -855,3 +866,207 @@ jobs:
echo "Cleaning up test environment..."
docker compose down -v --remove-orphans || true
rm -f .env

validate-evolution:
name: Validate Evolution API Configuration
runs-on: ubuntu-24.04

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Create .env file for testing
run: |
echo "Creating temporary .env file with test credentials..."
cat > .env << 'EOF'
# Test credentials for CI pipeline
POSTGRES_PASSWORD=test_postgres_password_12345678
EVOLUTION_DB_PASSWORD=test_evolution_password_12345678
EVOLUTION_API_KEY=test_evolution_api_key_12345678
EVOLUTION_WEBHOOK_URL=https://n8n.example.com.br/webhook/whatsapp-incoming
EVOLUTION_HOST=evolution.example.com.br
DATABASE_CONNECTION_CLIENT_NAME=evolution_api
N8N_DB_PASSWORD=test_n8n_password_12345678
REDIS_PASSWORD=test_redis_password_12345678901234567890
DOMAIN=example.com.br
EMAIL=admin@example.com.br
CORS_ALLOWED_ORIGINS=*
EOF

- name: Verify Evolution API configuration in docker-compose.yml
run: |
echo "Verifying Evolution API service is configured..."

# Check Evolution API image version is pinned correctly
if docker compose config | grep -q "image: atendai/evolution-api:v2.2.3"; then
echo "✅ Evolution API image correctly configured (atendai/evolution-api:v2.2.3)"
else
echo "❌ Evolution API image not configured correctly"
exit 1
fi

# Check Evolution API is on both networks
if docker compose config | grep -A 50 "evolution:" | grep -q "borgstack_internal"; then
echo "✅ Evolution API connected to borgstack_internal network"
else
echo "❌ Evolution API not connected to borgstack_internal network"
exit 1
fi

if docker compose config | grep -A 50 "evolution:" | grep -q "borgstack_external"; then
echo "✅ Evolution API connected to borgstack_external network"
else
echo "❌ Evolution API not connected to borgstack_external network"
exit 1
fi

# Verify volume naming convention
if docker compose config | grep -q "borgstack_evolution_instances"; then
echo "✅ Volume follows borgstack_ naming convention"
else
echo "❌ Volume does not follow naming convention"
exit 1
fi

# Verify no port exposure in production config
if docker compose config | grep -A 50 "evolution:" | grep -E "^\s+ports:" > /dev/null 2>&1; then
echo "❌ Evolution API has port exposure in production config (security violation)"
exit 1
else
echo "✅ No port exposure to host (security requirement met)"
fi

# Verify health check is configured
if docker compose config | grep -A 60 "evolution:" | grep -q "healthcheck:"; then
echo "✅ Health check configured for Evolution API"
else
echo "❌ Health check not configured for Evolution API"
exit 1
fi

- name: Verify Evolution API environment variables
run: |
echo "Verifying Evolution API environment variables configuration..."

# Check database connection variables
if docker compose config | grep -A 60 "evolution:" | grep -q "DATABASE_URL.*postgresql://evolution_user"; then
echo "✅ DATABASE_URL configured for evolution_user"
else
echo "❌ DATABASE_URL not configured correctly"
exit 1
fi

# Check Redis connection variables
if docker compose config | grep -A 60 "evolution:" | grep -q "REDIS_URI.*redis://"; then
echo "✅ REDIS_URI configured"
else
echo "❌ REDIS_URI not configured correctly"
exit 1
fi

# Check authentication variables
if docker compose config | grep -A 60 "evolution:" | grep -q "AUTHENTICATION_API_KEY"; then
echo "✅ AUTHENTICATION_API_KEY configured"
else
echo "❌ AUTHENTICATION_API_KEY not configured"
exit 1
fi

# Check webhook configuration
if docker compose config | grep -A 60 "evolution:" | grep -q "WEBHOOK_GLOBAL_URL"; then
echo "✅ WEBHOOK_GLOBAL_URL configured"
else
echo "❌ WEBHOOK_GLOBAL_URL not configured"
exit 1
fi

- name: Verify Evolution API depends_on configuration
run: |
echo "Verifying Evolution API service dependencies..."

# Check PostgreSQL dependency
if docker compose config | grep -A 80 "evolution:" | grep -A 10 "depends_on:" | grep -q "postgresql:"; then
echo "✅ Evolution API depends on postgresql"
else
echo "❌ Evolution API missing postgresql dependency"
exit 1
fi

# Check Redis dependency
if docker compose config | grep -A 80 "evolution:" | grep -A 10 "depends_on:" | grep -q "redis:"; then
echo "✅ Evolution API depends on redis"
else
echo "❌ Evolution API missing redis dependency"
exit 1
fi

- name: Verify Evolution API .env.example variables
run: |
echo "Verifying Evolution API variables in .env.example..."

if grep -q "EVOLUTION_HOST=" .env.example; then
echo "✅ EVOLUTION_HOST variable in .env.example"
else
echo "❌ EVOLUTION_HOST variable not found in .env.example"
exit 1
fi

if grep -q "EVOLUTION_API_KEY=" .env.example; then
echo "✅ EVOLUTION_API_KEY variable in .env.example"
else
echo "❌ EVOLUTION_API_KEY variable not found in .env.example"
exit 1
fi

if grep -q "EVOLUTION_DB_PASSWORD=" .env.example; then
echo "✅ EVOLUTION_DB_PASSWORD variable in .env.example"
else
echo "❌ EVOLUTION_DB_PASSWORD variable not found in .env.example"
exit 1
fi

if grep -q "EVOLUTION_WEBHOOK_URL=" .env.example; then
echo "✅ EVOLUTION_WEBHOOK_URL variable in .env.example"
else
echo "❌ EVOLUTION_WEBHOOK_URL variable not found in .env.example"
exit 1
fi

- name: Verify Evolution API validation test script exists
run: |
echo "Verifying Evolution API validation test script exists..."

if [ -f "tests/deployment/verify-evolution.sh" ]; then
echo "✅ verify-evolution.sh exists"
else
echo "❌ verify-evolution.sh not found"
exit 1
fi

if [ -x "tests/deployment/verify-evolution.sh" ]; then
echo "✅ verify-evolution.sh is executable"
else
echo "❌ verify-evolution.sh is not executable"
exit 1
fi

- name: Verify Evolution API documentation exists
run: |
echo "Verifying Evolution API documentation exists..."

if [ -f "config/evolution/README.md" ]; then
echo "✅ config/evolution/README.md exists"
else
echo "❌ config/evolution/README.md not found"
exit 1
fi

- name: Cleanup Evolution API test environment
if: always()
run: |
echo "Cleaning up test environment..."
docker compose down -v --remove-orphans || true
rm -f .env
73 changes: 73 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,44 @@ chmod +x scripts/bootstrap.sh
4. Create your first automation workflow
- **Example Workflows:** See `config/n8n/workflows/README.md` for import instructions

#### Evolution API - WhatsApp Business Gateway

- **URL:** `https://evolution.<your-domain>/manager` (Admin UI)
- **API Documentation:** `https://evolution.<your-domain>/docs`
- **API Key:** (from `EVOLUTION_API_KEY` in `.env`) - Required for ALL API operations
- **Webhook URL:** `https://n8n.<your-domain>/webhook/whatsapp-incoming` (configured automatically)
- **Multi-Instance Support:** Create separate WhatsApp instances for different business accounts
- **Getting Started:**
1. Access Evolution API Admin UI at `https://evolution.<your-domain>/manager`
2. Create WhatsApp instance (provide instance name, e.g., `customer_support`)
3. Scan QR code with WhatsApp (Settings → Linked Devices → Link a Device)
4. Verify connection status (instance state should be: `open`)
5. Import n8n webhook workflow: `config/n8n/workflows/03-whatsapp-evolution-incoming.json`
6. Test message sending/receiving
- **Detailed Setup Guide:** See `config/evolution/README.md` for complete instructions
- **n8n Integration:** Incoming WhatsApp messages → Evolution API → Webhook → n8n → Chatwoot/other services
- **Message Sending:** Use Evolution API HTTP nodes in n8n workflows to send WhatsApp messages

**API Usage Examples:**

```bash
# Create WhatsApp instance
curl -X POST "https://evolution.<your-domain>/instance/create" \
-H "Content-Type: application/json" \
-H "apikey: <EVOLUTION_API_KEY>" \
-d '{"instanceName": "customer_support", "qrcode": true, "integration": "WHATSAPP-BAILEYS"}'

# Send WhatsApp message
curl -X POST "https://evolution.<your-domain>/message/sendText/customer_support" \
-H "Content-Type: application/json" \
-H "apikey: <EVOLUTION_API_KEY>" \
-d '{"number": "5511987654321", "text": "Hello from BorgStack!"}'

# Check instance connection status
curl "https://evolution.<your-domain>/instance/connectionState/customer_support" \
-H "apikey: <EVOLUTION_API_KEY>"
```

### Troubleshooting

- **View logs:** `cat /tmp/borgstack-bootstrap.log`
Expand Down Expand Up @@ -184,6 +222,41 @@ docker compose exec postgresql psql -U postgres -c "\l" | grep n8n_db
docker compose logs n8n | grep -i "database\|postgres"
```

#### Evolution API Connection Issues

**Cannot access Evolution API Admin UI:**
```bash
# Check Evolution API container status
docker compose ps evolution

# Check Evolution API logs
docker compose logs evolution

# Verify DNS configuration
dig evolution.<your-domain>

# Check Caddy reverse proxy
docker compose logs caddy | grep evolution
```

**QR Code not displaying:**
1. Check Evolution API health: `docker compose ps evolution` (should show: healthy)
2. Verify database connection: `docker compose logs evolution | grep -i "database\|prisma"`
3. Check API key configuration: `grep EVOLUTION_API_KEY .env`

**WhatsApp connection fails after QR scan:**
1. Disconnect all WhatsApp Web sessions on your phone
2. Wait 5 minutes, then retry QR code scan
3. Check Evolution API logs: `docker compose logs evolution --tail 100`
4. Restart Evolution API: `docker compose restart evolution`

**Webhooks not delivered to n8n:**
1. Verify n8n webhook is active: `curl https://n8n.<your-domain>/webhook/whatsapp-incoming`
2. Check Evolution API webhook config: See `config/evolution/README.md` → Troubleshooting
3. Test webhook delivery: Send message to WhatsApp, check n8n executions

**For detailed troubleshooting:** See `config/evolution/README.md` → Troubleshooting section

**Redis/Queue errors:**
```bash
# Check Redis health
Expand Down
Loading