CI/CD Pipeline
Complete CI/CD implementation using GitHub Actions + Dokploy
CI/CD Pipeline Setup Guide
Complete CI/CD implementation using GitHub Actions + Dokploy
Pipeline: GitHub Actions (CI) → GitHub Container Registry (Artifacts) → Dokploy (CD) Deployment Time: 5-10 minutes (test → build → deploy) Zero-Downtime: Yes (rolling deployments with health checks)
Table of Contents
- Pipeline Architecture
- GitHub Actions Setup
- Dokploy Configuration
- Environment Strategy
- Deployment Workflows
- Troubleshooting
Pipeline Architecture
CI/CD Flow Diagram
┌──────────────────────────────────────────────────────┐
│ 1. DEVELOPER WORKFLOW │
├──────────────────────────────────────────────────────┤
│ git commit -m "feat: add feature" │
│ git push origin feature/new-feature │
│ │
│ → Creates PR to staging branch │
└──────────────────────────────────────────────────────┘
↓
┌──────────────────────────────────────────────────────┐
│ 2. GITHUB ACTIONS (CI PHASE) │
├──────────────────────────────────────────────────────┤
│ ✓ Checkout code │
│ ✓ Install dependencies (pnpm) │
│ ✓ Lint & Type Check (Biome) │
│ ✓ Run Tests (Vitest + E2E) │
│ ✓ Build Docker images (multi-stage) │
│ ✓ Security scan (Trivy) │
│ ✓ Push to GitHub Container Registry │
│ │
│ Duration: 5-8 minutes │
│ Parallelization: Build matrix (app, api, web) │
└──────────────────────────────────────────────────────┘
↓
┌──────────────────────────────────────────────────────┐
│ 3. PREVIEW DEPLOYMENT (for PRs) │
├──────────────────────────────────────────────────────┤
│ Dokploy creates ephemeral environment │
│ URL: https://pr-123.staging.your-domain.com │
│ │
│ Auto-cleanup: 7 days or on PR merge │
└──────────────────────────────────────────────────────┘
↓
┌──────────────────────────────────────────────────────┐
│ 4. STAGING DEPLOYMENT (on merge to staging) │
├──────────────────────────────────────────────────────┤
│ Dokploy webhook triggered │
│ → Pull latest images from registry │
│ → Run database migrations (if needed) │
│ → Deploy with zero downtime │
│ → Health check validation │
│ │
│ URL: https://staging.your-domain.com │
│ Duration: 2-3 minutes │
└──────────────────────────────────────────────────────┘
↓
┌──────────────────────────────────────────────────────┐
│ 5. PRODUCTION DEPLOYMENT (on merge to main) │
├──────────────────────────────────────────────────────┤
│ Manual approval required (GitHub Environment) │
│ → Dokploy webhook triggered │
│ → Rolling deployment (2 replicas) │
│ → Health checks (30s interval, 3 retries) │
│ → Automatic rollback on failure │
│ → Slack notification on completion │
│ │
│ URL: https://app.your-domain.com │
│ Duration: 2-3 minutes │
└──────────────────────────────────────────────────────┘GitHub Actions Setup
Prerequisites
- GitHub Repository Secrets
Navigate to: Settings → Secrets and variables → Actions
Add these secrets:
DOKPLOY_API_KEY # Dokploy API key (generate in Dokploy UI)
SLACK_WEBHOOK_URL # Slack incoming webhook URL
GHCR_PAT # GitHub Personal Access Token (packages:write)- GitHub Environments
Create these environments in: Settings → Environments
- staging (no approval required)
- production (required reviewers: 1+)
GitHub Actions Workflow
File: .github/workflows/deploy.yml
name: CI/CD Pipeline
on:
push:
branches: [main, staging, develop]
pull_request:
branches: [main, staging]
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
# ═════════════════════════════════════════════════════
# CI PHASE: Testing & Quality Checks
# ═════════════════════════════════════════════════════
test:
name: Test & Lint
runs-on: ubuntu-latest
timeout-minutes: 15
services:
postgres:
image: postgres:18-alpine
env:
POSTGRES_USER: test
POSTGRES_PASSWORD: test
POSTGRES_DB: ripplecore_test
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
redis:
image: redis:7-alpine
ports:
- 6379:6379
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v2
with:
version: 9
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'
- name: Install Dependencies
run: pnpm install --frozen-lockfile
- name: Lint & Type Check
run: pnpm check
- name: Run Unit Tests
run: pnpm test
env:
DATABASE_URL: postgresql://test:test@localhost:5432/ripplecore_test
REDIS_URL: redis://localhost:6379
- name: Run E2E Tests
run: pnpm test:e2e
env:
DATABASE_URL: postgresql://test:test@localhost:5432/ripplecore_test
REDIS_URL: redis://localhost:6379
BETTER_AUTH_SECRET: test-secret-for-ci-only
BETTER_AUTH_URL: http://localhost:3000
# ═════════════════════════════════════════════════════
# BUILD PHASE: Docker Images
# ═════════════════════════════════════════════════════
build:
name: Build Docker Images
needs: test
runs-on: ubuntu-latest
timeout-minutes: 20
permissions:
contents: read
packages: write
strategy:
matrix:
app: [app, api, web]
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract Docker Metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-${{ matrix.app }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=sha,prefix={{branch}}-
type=raw,value=latest,enable={{is_default_branch}}
- name: Build and Push Docker Image
uses: docker/build-push-action@v5
with:
context: .
file: apps/${{ matrix.app }}/Dockerfile
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
build-args: |
NODE_ENV=production
# ═════════════════════════════════════════════════════
# SECURITY PHASE: Vulnerability Scanning
# ═════════════════════════════════════════════════════
security:
name: Security Scan
needs: build
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: read
security-events: write
strategy:
matrix:
app: [app, api, web]
steps:
- name: Run Trivy Vulnerability Scanner
uses: aquasecurity/trivy-action@master
with:
image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-${{ matrix.app }}:${{ github.sha }}
format: 'sarif'
output: 'trivy-results-${{ matrix.app }}.sarif'
severity: 'CRITICAL,HIGH'
- name: Upload Trivy Results to GitHub Security
uses: github/codeql-action/upload-sarif@v2
if: always()
with:
sarif_file: 'trivy-results-${{ matrix.app }}.sarif'
category: 'trivy-${{ matrix.app }}'
# ═════════════════════════════════════════════════════
# PREVIEW DEPLOYMENT: PR Environments
# ═════════════════════════════════════════════════════
deploy-preview:
name: Deploy Preview Environment
needs: [build, security]
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Trigger Dokploy Preview Deployment
run: |
PR_NUMBER=${{ github.event.pull_request.number }}
curl -X POST https://dokploy.your-domain.com/api/preview/deploy \
-H "Authorization: Bearer ${{ secrets.DOKPLOY_API_KEY }}" \
-H "Content-Type: application/json" \
-d '{
"pr": "'$PR_NUMBER'",
"branch": "${{ github.head_ref }}",
"imageTag": "${{ github.sha }}"
}'
- name: Wait for Preview Deployment
run: |
PR_NUMBER=${{ github.event.pull_request.number }}
max_attempts=30
attempt=0
while [ $attempt -lt $max_attempts ]; do
if curl -f https://pr-$PR_NUMBER.staging.your-domain.com/api/health; then
echo "✅ Preview environment is healthy"
exit 0
fi
attempt=$((attempt + 1))
echo "Waiting for preview environment... ($attempt/$max_attempts)"
sleep 10
done
echo "❌ Preview deployment health check failed"
exit 1
- name: Comment PR with Preview URL
uses: actions/github-script@v6
with:
script: |
const prNumber = context.payload.pull_request.number;
const previewUrl = `https://pr-${prNumber}.staging.your-domain.com`;
github.rest.issues.createComment({
issue_number: prNumber,
owner: context.repo.owner,
repo: context.repo.repo,
body: `
## 🚀 Preview Deployment Ready
Your changes have been deployed to a preview environment:
**URL**: ${previewUrl}
This environment will be automatically deleted when:
- The PR is merged or closed
- 7 days have passed since last update
---
<sub>Deployment ID: \`${{ github.sha }}\` | Build: [#${{ github.run_number }}](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})</sub>
`
});
# ═════════════════════════════════════════════════════
# STAGING DEPLOYMENT
# ═════════════════════════════════════════════════════
deploy-staging:
name: Deploy to Staging
needs: [build, security]
if: github.ref == 'refs/heads/staging' && github.event_name == 'push'
runs-on: ubuntu-latest
timeout-minutes: 10
environment: staging
steps:
- name: Trigger Dokploy Staging Deployment
run: |
curl -X POST https://dokploy.your-domain.com/api/deploy \
-H "Authorization: Bearer ${{ secrets.DOKPLOY_API_KEY }}" \
-H "Content-Type: application/json" \
-d '{
"project": "ripplecore-staging",
"services": ["app", "api", "web"],
"imageTag": "${{ github.sha }}"
}'
- name: Wait for Staging Health Checks
run: |
services=("https://staging.your-domain.com" "https://api.staging.your-domain.com" "https://www.staging.your-domain.com")
max_attempts=30
for service in "${services[@]}"; do
attempt=0
echo "Checking $service..."
while [ $attempt -lt $max_attempts ]; do
if curl -f $service/api/health; then
echo "✅ $service is healthy"
break
fi
attempt=$((attempt + 1))
sleep 10
done
if [ $attempt -eq $max_attempts ]; then
echo "❌ $service health check failed"
exit 1
fi
done
- name: Notify Slack (Staging)
if: always()
uses: 8398a7/action-slack@v3
with:
status: ${{ job.status }}
text: |
Staging Deployment: ${{ job.status }}
Branch: staging
Commit: ${{ github.sha }}
Author: ${{ github.actor }}
webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }}
channel: '#deployments'
# ═════════════════════════════════════════════════════
# PRODUCTION DEPLOYMENT
# ═════════════════════════════════════════════════════
deploy-production:
name: Deploy to Production
needs: [build, security]
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
runs-on: ubuntu-latest
timeout-minutes: 15
environment: production # Requires manual approval
steps:
- name: Trigger Dokploy Production Deployment
id: deploy
run: |
curl -X POST https://dokploy.your-domain.com/api/deploy \
-H "Authorization: Bearer ${{ secrets.DOKPLOY_API_KEY }}" \
-H "Content-Type: application/json" \
-d '{
"project": "ripplecore-production",
"services": ["app", "api", "web"],
"imageTag": "${{ github.sha }}",
"strategy": "rolling",
"healthCheck": {
"enabled": true,
"path": "/api/health",
"interval": 30,
"retries": 3
}
}'
- name: Wait for Production Health Checks
run: |
services=("https://app.your-domain.com" "https://api.your-domain.com" "https://www.your-domain.com")
max_attempts=30
for service in "${services[@]}"; do
attempt=0
echo "Checking $service..."
while [ $attempt -lt $max_attempts ]; do
response=$(curl -s -o /dev/null -w "%{http_code}" $service/api/health)
if [ "$response" = "200" ]; then
echo "✅ $service is healthy (HTTP 200)"
break
fi
attempt=$((attempt + 1))
echo "Waiting for $service... ($attempt/$max_attempts) - HTTP $response"
sleep 10
done
if [ $attempt -eq $max_attempts ]; then
echo "❌ $service health check failed after $max_attempts attempts"
echo "Initiating automatic rollback..."
curl -X POST https://dokploy.your-domain.com/api/rollback \
-H "Authorization: Bearer ${{ secrets.DOKPLOY_API_KEY }}" \
-H "Content-Type: application/json" \
-d '{"project": "ripplecore-production"}'
exit 1
fi
done
- name: Run Smoke Tests
run: |
# Basic smoke tests after deployment
echo "Running smoke tests..."
# Test authentication endpoint
curl -f https://app.your-domain.com/api/auth/session || exit 1
# Test API health
curl -f https://api.your-domain.com/api/health || exit 1
# Test database connectivity (via health endpoint)
response=$(curl -s https://app.your-domain.com/api/health)
if echo "$response" | grep -q '"database":{"status":"ok"}'; then
echo "✅ Database connectivity verified"
else
echo "❌ Database connectivity check failed"
exit 1
fi
echo "✅ All smoke tests passed"
- name: Notify Slack (Production Success)
if: success()
uses: 8398a7/action-slack@v3
with:
status: custom
custom_payload: |
{
"text": "🚀 Production Deployment Successful",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Production Deployment Successful* 🎉"
}
},
{
"type": "section",
"fields": [
{
"type": "mrkdwn",
"text": "*Branch:*\nmain"
},
{
"type": "mrkdwn",
"text": "*Commit:*\n${{ github.sha }}"
},
{
"type": "mrkdwn",
"text": "*Author:*\n${{ github.actor }}"
},
{
"type": "mrkdwn",
"text": "*Status:*\n✅ Healthy"
}
]
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "<https://app.your-domain.com|View Production>"
}
}
]
}
webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }}
channel: '#deployments'
- name: Notify Slack (Production Failure)
if: failure()
uses: 8398a7/action-slack@v3
with:
status: custom
custom_payload: |
{
"text": "🚨 Production Deployment Failed",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Production Deployment Failed* 🚨"
}
},
{
"type": "section",
"fields": [
{
"type": "mrkdwn",
"text": "*Branch:*\nmain"
},
{
"type": "mrkdwn",
"text": "*Commit:*\n${{ github.sha }}"
},
{
"type": "mrkdwn",
"text": "*Author:*\n${{ github.actor }}"
},
{
"type": "mrkdwn",
"text": "*Status:*\n❌ Failed (Rollback Initiated)"
}
]
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "<${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|View Logs>"
}
}
]
}
webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }}
channel: '#deployments'Dokploy Configuration
Dokploy Installation (CI/CD Server)
# SSH into CI/CD server
ssh root@cicd-server-ip
# Install Dokploy (includes Docker, Traefik, PostgreSQL)
curl -sSL https://dokploy.com/install.sh | sh
# Access Dokploy UI
# URL: https://cicd-server-ip:3000
# Create admin account on first loginProject Configuration (Via Dokploy UI)
1. Create Production Project
Settings → New Project:
Project Name: ripplecore-production
Description: RippleCore production environment2. Add Applications
For Each App (app, api, web):
Application Name: ripplecore-app # or api, web
Type: Application (Docker)
Source:
Repository: https://github.com/your-org/ripplecore-forge
Branch: main
Build Path: apps/app # or apps/api, apps/web
Build:
Type: Dockerfile
Dockerfile Path: apps/app/Dockerfile
Build Context: .
Build Args:
- NODE_ENV=production
Deploy:
Replicas: 2 # Zero-downtime deployments
Resources:
Memory Limit: 3GB
CPU Limit: 1.5
Health Check:
Enabled: true
Path: /api/health
Interval: 30s
Timeout: 5s
Retries: 3
Start Period: 60s
Environment Variables:
DATABASE_URL: postgresql://ripplecore:<secret>@10.0.1.3:5432/ripplecore_prod
REDIS_URL: redis://:<secret>@10.0.1.3:6379
BETTER_AUTH_SECRET: <generate-with-cli>
BETTER_AUTH_URL: https://app.your-domain.com
BETTER_AUTH_TRUST_HOST: true
NODE_ENV: production
NEXT_PUBLIC_APP_URL: https://app.your-domain.com
Domains:
- Domain: app.your-domain.com
SSL: Enabled (Let's Encrypt)
Email: admin@your-domain.com
Deployment Strategy:
Type: Rolling Update
Max Surge: 1
Max Unavailable: 03. Enable GitHub Webhooks
Settings → Webhooks:
Enable GitHub Webhook: true
Webhook URL: https://dokploy.your-domain.com/api/webhook/github
Secret: <generate-random-secret>
# Add webhook in GitHub:
# Repo → Settings → Webhooks → Add webhook
# Payload URL: https://dokploy.your-domain.com/api/webhook/github
# Content type: application/json
# Secret: <same-as-above>
# Events: Just the push eventEnvironment Strategy
Branch-to-Environment Mapping
| Branch | Environment | Auto-Deploy | Approval | Domain |
|---|---|---|---|---|
develop | Development (local) | No | No | localhost:3000 |
feature/* | Preview (PR) | Yes | No | pr-123.staging.domain.com |
staging | Staging | Yes | No | staging.domain.com |
main | Production | Yes | Yes (1 reviewer) | app.domain.com |
Environment Variables Matrix
Shared Variables (all environments):
NODE_ENV=production
NEXT_TELEMETRY_DISABLED=1Environment-Specific:
| Variable | Development | Staging | Production |
|---|---|---|---|
DATABASE_URL | localhost:5432 | 10.0.2.2:5432 | 10.0.1.3:5432 |
REDIS_URL | localhost:6379 | 10.0.2.2:6379 | 10.0.1.3:6379 |
BETTER_AUTH_URL | http://localhost:3000 | https://staging.domain.com | https://app.domain.com |
BETTER_AUTH_TRUST_HOST | false | true | true |
STRICT_HEALTH_CHECK | false | false | true |
Deployment Workflows
Standard Deployment Flow
1. Feature Development (developer workflow):
# Create feature branch
git checkout -b feature/new-feature
# Make changes, commit
git add .
git commit -m "feat: add new feature"
# Push to GitHub
git push origin feature/new-feature
# Create PR to staging
# → GitHub Actions runs tests & builds
# → Preview environment created (pr-123.staging.domain.com)2. Staging Deployment (merge to staging):
# After PR review and approval
git checkout staging
git merge feature/new-feature
git push origin staging
# → GitHub Actions: test + build + push images
# → Dokploy: deploy to staging
# → Health checks validate deployment
# → Slack notification sent3. Production Deployment (merge to main):
# After QA approval on staging
git checkout main
git merge staging
git push origin main
# → GitHub Actions: test + build + push images
# → Wait for manual approval (GitHub Environment protection)
# → Dokploy: rolling deployment to production
# → Health checks + smoke tests
# → Automatic rollback on failure
# → Slack notification sentEmergency Hotfix Flow
# Create hotfix branch from main
git checkout -b hotfix/critical-fix main
# Make minimal changes
git add .
git commit -m "hotfix: fix critical bug"
# Push and create PR directly to main
git push origin hotfix/critical-fix
# → Fast-track review (1 approver)
# → Merge to main → Auto-deploy to production
# → Backport to staging after production validationRollback Procedure
Automatic Rollback (health check failure):
- Dokploy automatically reverts to previous deployment
- Previous Docker images redeployed
- Health checks validate rollback successful
Manual Rollback (via Dokploy UI):
1. Navigate to: Projects → ripplecore-production → app
2. Click: Deployments tab
3. Select: Previous successful deployment
4. Click: Rollback to this deployment
5. Confirm: Rollback initiated
6. Verify: Health checks passManual Rollback (via Git):
# Revert to previous commit
git revert HEAD
git push origin main
# → Triggers new deployment with reverted changesTroubleshooting
Common Issues
Issue: GitHub Actions Failing at Build Step
Symptoms:
Error: Failed to build Docker image
Context: COPY failed: file not foundSolution:
# Verify Dockerfile context is correct
# In Dockerfile:
COPY apps/app/package.json ./package.json # ❌ Wrong (missing context)
COPY package.json ./package.json # ✅ Correct (buildx context aware)
# Check build context in workflow
# In .github/workflows/deploy.yml:
context: . # Root of repo
file: apps/app/DockerfileIssue: Dokploy Deployment Stuck at "Pulling Image"
Symptoms:
- Deployment status: "Pulling image from registry"
- Health checks never start
Solution:
# 1. Verify image exists in registry
docker pull ghcr.io/your-org/ripplecore-app:sha-abc123
# 2. Check Dokploy server can access registry
ssh root@cicd-server
docker login ghcr.io -u your-username -p <token>
# 3. Manually pull image to verify network
docker pull ghcr.io/your-org/ripplecore-app:latestIssue: Health Check Failing After Deployment
Symptoms:
Health check failed: Connection refused
URL: https://app.your-domain.com/api/healthDebugging Steps:
# 1. Check container is running
docker ps | grep ripplecore-app
# 2. Check container logs
docker logs ripplecore-app --tail 100
# 3. Test health endpoint locally
docker exec ripplecore-app curl http://localhost:3000/api/health
# 4. Verify environment variables
docker exec ripplecore-app env | grep DATABASE_URL
# 5. Check Traefik routing
docker logs traefik | grep "app.your-domain.com"Issue: Preview Environment Not Created
Symptoms:
- PR comment not posted with preview URL
- No preview environment visible in Dokploy
Solution:
# 1. Verify Dokploy webhook received PR event
# Dokploy UI → Webhooks → Recent Deliveries
# 2. Check GitHub Actions logs for webhook call
# Actions → deploy-preview job → "Trigger Dokploy Preview Deployment"
# 3. Verify API key is correct
curl -X POST https://dokploy.your-domain.com/api/preview/test \
-H "Authorization: Bearer YOUR_API_KEY"
# Should return: {"status": "ok"}Performance Optimization
Reduce Build Time (GitHub Actions)
Current: ~8-10 minutes per build
Optimizations:
# 1. Enable BuildKit caching
- name: Build Docker Image
uses: docker/build-push-action@v5
with:
cache-from: type=gha
cache-to: type=gha,mode=max # ← Aggressive caching
# 2. Use matrix builds (parallel)
strategy:
matrix:
app: [app, api, web] # ← Builds in parallel
# 3. Skip unnecessary steps on PR
if: github.event_name != 'pull_request' # Skip security scan on PRsExpected: ~5-6 minutes per build
Reduce Deployment Time (Dokploy)
Current: ~3-5 minutes per deployment
Optimizations:
# 1. Pre-pull images during build (parallel)
# In Dokploy config:
prePullImages: true
# 2. Reduce health check interval
healthCheck:
interval: 10s # Down from 30s
startPeriod: 30s # Down from 60s
# 3. Use rolling deployment (already configured)
strategy: rolling
maxSurge: 1
maxUnavailable: 0Expected: ~2-3 minutes per deployment
Monitoring Deployments
GitHub Actions Dashboard
View Pipeline Status:
- Navigate to: Actions tab in GitHub repository
- Filter by workflow:
CI/CD Pipeline - View deployment history, success rates, duration trends
Dokploy Deployment Logs
Real-Time Logs:
# Access Dokploy UI
https://dokploy.your-domain.com
# Navigate to: Projects → ripplecore-production → app → Logs
# View real-time logs during deploymentCLI Access:
# SSH into CI/CD server
ssh root@cicd-server-ip
# View live deployment logs
dokploy logs ripplecore-production app --followSlack Notifications
Configured Channels:
#deployments- All deployment notifications#alerts- Critical deployment failures only
Notification Types:
- ✅ Staging deployment successful
- ✅ Production deployment successful
- ❌ Deployment failed (with logs link)
- 🔄 Rollback initiated
Related Documentation
- Infrastructure Overview: See
ARCHITECTURE.md - Monitoring Setup: See
MONITORING.md - Backup Procedures: See
BACKUP_RECOVERY.md - Deployment Checklist: See
DEPLOYMENT_CHECKLIST.md
Document Version: 1.0 Last Updated: 2025-01-23 Review Cycle: After major pipeline changes