name: Deploy to Production on: push: branches: - main jobs: deploy: runs-on: ubuntu-latest steps: - name: Checkout code run: | git clone "http://172.17.0.1:3000/${{ github.repository }}.git" . git checkout "${{ github.sha }}" - name: Create .env.production from secrets run: | cat > .env.production << 'ENVEOF' DOMAIN=${{ secrets.DOMAIN }} FRONTEND_HOST=${{ secrets.FRONTEND_HOST }} ENVIRONMENT=production PROJECT_NAME=${{ secrets.PROJECT_NAME }} STACK_NAME=${{ secrets.STACK_NAME }} BACKEND_CORS_ORIGINS=${{ secrets.BACKEND_CORS_ORIGINS }} SECRET_KEY=${{ secrets.SECRET_KEY }} FIRST_SUPERUSER=${{ secrets.FIRST_SUPERUSER }} FIRST_SUPERUSER_PASSWORD=${{ secrets.FIRST_SUPERUSER_PASSWORD }} SMTP_HOST=${{ secrets.SMTP_HOST }} SMTP_USER=${{ secrets.SMTP_USER }} SMTP_PASSWORD=${{ secrets.SMTP_PASSWORD }} EMAILS_FROM_EMAIL=${{ secrets.EMAILS_FROM_EMAIL }} SMTP_TLS=${{ secrets.SMTP_TLS }} SMTP_SSL=${{ secrets.SMTP_SSL }} SMTP_PORT=${{ secrets.SMTP_PORT }} POSTGRES_SERVER=${{ secrets.POSTGRES_SERVER }} POSTGRES_PORT=${{ secrets.POSTGRES_PORT }} POSTGRES_DB=${{ secrets.POSTGRES_DB }} POSTGRES_USER=${{ secrets.POSTGRES_USER }} POSTGRES_PASSWORD=${{ secrets.POSTGRES_PASSWORD }} SENTRY_DSN=${{ secrets.SENTRY_DSN }} DOCKER_IMAGE_BACKEND=${{ secrets.DOCKER_IMAGE_BACKEND }} DOCKER_IMAGE_FRONTEND=${{ secrets.DOCKER_IMAGE_FRONTEND }} ENVEOF # Fallback defaults if image name secrets are empty sed -i 's/^DOCKER_IMAGE_BACKEND=$/DOCKER_IMAGE_BACKEND=backend/' .env.production sed -i 's/^DOCKER_IMAGE_FRONTEND=$/DOCKER_IMAGE_FRONTEND=frontend/' .env.production - name: Build Docker images run: docker compose --env-file .env.production -f compose.prod.yml build - name: Stop existing services run: docker compose --env-file .env.production -f compose.prod.yml down --remove-orphans || true - name: Start services run: docker compose --env-file .env.production -f compose.prod.yml up -d - name: Wait for backend health check run: | echo "Waiting for backend to be healthy..." for i in $(seq 1 30); do if curl -sf http://127.0.0.1:18000/api/v1/utils/health-check/ > /dev/null 2>&1; then echo "✅ Backend is healthy!" exit 0 fi echo "Attempt $i/30 - waiting 10s..." sleep 10 done echo "❌ Backend health check failed after 300s" docker compose --env-file .env.production -f compose.prod.yml logs backend exit 1 - name: Verify frontend run: | if curl -sf http://127.0.0.1:3001 > /dev/null 2>&1; then echo "✅ Frontend is accessible!" else echo "❌ Frontend is not accessible" docker compose --env-file .env.production -f compose.prod.yml logs frontend exit 1 fi - name: Cleanup old Docker images run: docker image prune -f || true