name: Deploy API Server on: push: branches: [main] jobs: build-and-deploy: runs-on: ubuntu-latest steps: - name: Checkout latest code run: | if [ -d /tmp/api-server ]; then cd /tmp/api-server && git pull else git clone http://localhost:3000/suche-Hermes/api-server.git /tmp/api-server fi - name: Build Docker image run: cd /tmp/api-server && docker build -t zhixi-api:latest . - name: Stop old container run: docker stop zhixi-api 2>/dev/null || true - name: Remove old container run: docker rm zhixi-api 2>/dev/null || true - name: Ensure infrastructure is ready run: | # Create network if missing docker network inspect zhixi-net >/dev/null 2>&1 || docker network create zhixi-net # Start MySQL + Redis via docker compose (try common locations) for dir in /opt/zhixi /root/zhixi /tmp/api-server; do if [ -f "$dir/docker-compose.yml" ]; then cd "$dir" && docker compose up -d mysql redis 2>/dev/null || true break fi done sleep 5 - name: Resolve failed migrations run: | MYSQL_PASS=$(docker exec mysql-zhixi printenv MYSQL_PASSWORD 2>/dev/null || echo "Zhixi@2026!App") MYSQL_CMD="docker exec mysql-zhixi mysql -u zhixi_user -p${MYSQL_PASS} zhixi" # Check for failed/stuck migrations FAILED=$($MYSQL_CMD -N -e \ "SELECT migration_name FROM _prisma_migrations WHERE logs LIKE '%failed%' LIMIT 1;" 2>/dev/null || true) if [ -n "$FAILED" ]; then echo "[deploy] Found failed migration: $FAILED, cleaning up partially-created objects..." # Drop new tables from the migration (IF EXISTS is safe) $MYSQL_CMD -e "DROP TABLE IF EXISTS AiUsageLog;" 2>/dev/null || true $MYSQL_CMD -e "DROP TABLE IF EXISTS WaitlistEntry;" 2>/dev/null || true # Drop new columns from UploadedFile (without IF EXISTS for MySQL < 8.0.29 compat) $MYSQL_CMD -e "ALTER TABLE UploadedFile DROP COLUMN objectKey;" 2>/dev/null || true $MYSQL_CMD -e "ALTER TABLE UploadedFile DROP COLUMN bucket;" 2>/dev/null || true # Drop index (ignore error if not exists) $MYSQL_CMD -e "DROP INDEX UploadedFile_objectKey_idx ON UploadedFile;" 2>/dev/null || true # Remove the failed migration record so Prisma can re-apply it $MYSQL_CMD -e "DELETE FROM _prisma_migrations WHERE migration_name = '$FAILED';" echo "[deploy] Cleaned up failed migration $FAILED" else echo "[deploy] No failed migrations found" fi - name: Start new container run: | ENV_FILE="" if [ -f /etc/zhixi/.env.production ]; then ENV_FILE="--env-file /etc/zhixi/.env.production" fi docker run -d \ --name zhixi-api \ --network zhixi-net \ --restart unless-stopped \ -p 3001:3000 \ $ENV_FILE \ zhixi-api:latest - name: Deploy RAG Worker run: | WORKER_DIR="/opt/zhixi/backend/rag-worker" mkdir -p "$WORKER_DIR" # Sync worker code from checkout (exclude .env to avoid overwriting secrets) rsync -av --delete --exclude='.env' --exclude='__pycache__' \ /tmp/api-server/rag-worker/ "$WORKER_DIR/" # Copy service file and reload cp "$WORKER_DIR/zhixi-worker.service" /etc/systemd/system/ systemctl daemon-reload systemctl restart zhixi-worker sleep 8 systemctl is-active zhixi-worker && echo "[deploy] zhixi-worker active OK" || { echo "[deploy] zhixi-worker FAILED, checking logs:" journalctl -u zhixi-worker --no-pager -n 30 exit 1 } - name: Health check run: | sleep 8 curl -f http://localhost:3001/health || (docker logs zhixi-api --tail 30 && exit 1)