mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-15 03:01:09 +02:00
chore: remove Hetzner legacy artifacts and update docs for Mac Mini self-hosting
Deleted files: - docker/caddy/Caddyfile.production + Caddyfile.staging (Hetzner reverse proxy configs) - scripts/deploy/ (deploy-hetzner.sh, build-and-push.sh, health-check.sh, migrate-db.sh, rollback.sh) - scripts/generate-staging-secrets.sh - cicd/ directory (11 Hetzner CI/CD planning docs) - CI_CD_IMPLEMENTATION_SUMMARY.md, CI_CD_README.md, FILES_CREATED.md, HIVE_MIND_FINAL_REPORT.md Updated docs: - CLAUDE.md: Remove Hetzner Object Storage references, update to MinIO - docs/ANALYTICS.md: Cloudflare Tunnel instead of Caddy - docs/URL_SCHEMA.md: Mac Mini + Cloudflare Tunnel instead of Hetzner IP - .env.development: Remove "Hetzner in production" comments Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
94fead0873
commit
cc5ba3bb90
27 changed files with 19 additions and 8863 deletions
|
|
@ -1,170 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Build and push Docker images for manacore services
|
||||
# Usage: ./build-and-push.sh [service] [tag]
|
||||
# Example: ./build-and-push.sh chat-backend v1.0.0
|
||||
# Example: ./build-and-push.sh all latest
|
||||
|
||||
set -e
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Configuration
|
||||
DOCKER_REGISTRY=${DOCKER_REGISTRY:-"wuesteon"}
|
||||
SERVICE=${1:-"all"}
|
||||
TAG=${2:-"latest"}
|
||||
PLATFORM=${PLATFORM:-"linux/amd64"}
|
||||
|
||||
# Function to print colored output
|
||||
log_info() {
|
||||
echo -e "${GREEN}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
log_warn() {
|
||||
echo -e "${YELLOW}[WARN]${NC} $1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
}
|
||||
|
||||
# Function to build and push a service
|
||||
build_and_push() {
|
||||
local service=$1
|
||||
local dockerfile=$2
|
||||
local context=${3:-.}
|
||||
local image_name="${DOCKER_REGISTRY}/${service}"
|
||||
|
||||
log_info "Building ${service}..."
|
||||
|
||||
# Build the image
|
||||
if docker buildx build \
|
||||
--platform ${PLATFORM} \
|
||||
--tag "${image_name}:${TAG}" \
|
||||
--tag "${image_name}:latest" \
|
||||
--file "${dockerfile}" \
|
||||
--progress plain \
|
||||
${context}; then
|
||||
|
||||
log_info "Successfully built ${service}"
|
||||
|
||||
# Push the image
|
||||
log_info "Pushing ${service} to registry..."
|
||||
|
||||
if docker push "${image_name}:${TAG}" && docker push "${image_name}:latest"; then
|
||||
log_info "Successfully pushed ${service}"
|
||||
return 0
|
||||
else
|
||||
log_error "Failed to push ${service}"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
log_error "Failed to build ${service}"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to build all services
|
||||
build_all() {
|
||||
local services=(
|
||||
"mana-core-auth:services/mana-core-auth/Dockerfile"
|
||||
"maerchenzauber-backend:apps/maerchenzauber/apps/backend/Dockerfile"
|
||||
"chat-backend:apps/chat/apps/backend/Dockerfile"
|
||||
"manadeck-backend:apps/manadeck/apps/backend/Dockerfile"
|
||||
"nutriphi-backend:apps/nutriphi/apps/backend/Dockerfile"
|
||||
"news-api:apps/news/apps/api/Dockerfile"
|
||||
)
|
||||
|
||||
local failed_services=()
|
||||
|
||||
for service_config in "${services[@]}"; do
|
||||
IFS=':' read -r service dockerfile <<< "$service_config"
|
||||
|
||||
if [ -f "$dockerfile" ]; then
|
||||
if ! build_and_push "$service" "$dockerfile" "."; then
|
||||
failed_services+=("$service")
|
||||
fi
|
||||
else
|
||||
log_warn "Dockerfile not found for ${service}: ${dockerfile}"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
done
|
||||
|
||||
# Report results
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
if [ ${#failed_services[@]} -eq 0 ]; then
|
||||
log_info "All services built and pushed successfully!"
|
||||
return 0
|
||||
else
|
||||
log_error "Failed to build/push the following services:"
|
||||
for service in "${failed_services[@]}"; do
|
||||
echo " - ${service}"
|
||||
done
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Check if Docker is installed
|
||||
if ! command -v docker &> /dev/null; then
|
||||
log_error "Docker is not installed or not in PATH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if buildx is available
|
||||
if ! docker buildx version &> /dev/null; then
|
||||
log_error "Docker buildx is not available"
|
||||
log_info "Install it with: docker buildx install"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Login to Docker registry
|
||||
if [ -n "${DOCKER_USERNAME}" ] && [ -n "${DOCKER_PASSWORD}" ]; then
|
||||
log_info "Logging in to Docker registry..."
|
||||
echo "${DOCKER_PASSWORD}" | docker login -u "${DOCKER_USERNAME}" --password-stdin
|
||||
fi
|
||||
|
||||
# Main execution
|
||||
log_info "Starting build and push process..."
|
||||
log_info "Registry: ${DOCKER_REGISTRY}"
|
||||
log_info "Tag: ${TAG}"
|
||||
log_info "Platform: ${PLATFORM}"
|
||||
echo ""
|
||||
|
||||
if [ "$SERVICE" == "all" ]; then
|
||||
build_all
|
||||
else
|
||||
# Build specific service
|
||||
case "$SERVICE" in
|
||||
"mana-core-auth")
|
||||
build_and_push "mana-core-auth" "services/mana-core-auth/Dockerfile" "."
|
||||
;;
|
||||
"maerchenzauber-backend")
|
||||
build_and_push "maerchenzauber-backend" "apps/maerchenzauber/apps/backend/Dockerfile" "."
|
||||
;;
|
||||
"chat-backend")
|
||||
build_and_push "chat-backend" "apps/chat/apps/backend/Dockerfile" "."
|
||||
;;
|
||||
"manadeck-backend")
|
||||
build_and_push "manadeck-backend" "apps/manadeck/apps/backend/Dockerfile" "."
|
||||
;;
|
||||
"nutriphi-backend")
|
||||
build_and_push "nutriphi-backend" "apps/nutriphi/apps/backend/Dockerfile" "."
|
||||
;;
|
||||
"news-api")
|
||||
build_and_push "news-api" "apps/news/apps/api/Dockerfile" "."
|
||||
;;
|
||||
*)
|
||||
log_error "Unknown service: $SERVICE"
|
||||
echo "Available services: all, mana-core-auth, maerchenzauber-backend, chat-backend, manadeck-backend, nutriphi-backend, news-api"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
log_info "Build and push process completed!"
|
||||
|
|
@ -1,201 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Deploy to Hetzner server via SSH
|
||||
# Usage: ./deploy-hetzner.sh [environment] [service]
|
||||
# Example: ./deploy-hetzner.sh staging all
|
||||
# Example: ./deploy-hetzner.sh production chat-backend
|
||||
|
||||
set -e
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
# Configuration
|
||||
ENVIRONMENT=${1:-"staging"}
|
||||
SERVICE=${2:-"all"}
|
||||
|
||||
# Environment-specific variables
|
||||
if [ "$ENVIRONMENT" == "production" ]; then
|
||||
SSH_HOST=${PRODUCTION_HOST}
|
||||
SSH_USER=${PRODUCTION_USER}
|
||||
SSH_KEY=${PRODUCTION_SSH_KEY}
|
||||
DEPLOY_DIR="~/manacore-production"
|
||||
COMPOSE_FILE="docker-compose.production.yml"
|
||||
else
|
||||
SSH_HOST=${STAGING_HOST}
|
||||
SSH_USER=${STAGING_USER}
|
||||
SSH_KEY=${STAGING_SSH_KEY}
|
||||
DEPLOY_DIR="~/manacore-staging"
|
||||
COMPOSE_FILE="docker-compose.staging.yml"
|
||||
fi
|
||||
|
||||
# Function to print colored output
|
||||
log_info() {
|
||||
echo -e "${GREEN}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
log_warn() {
|
||||
echo -e "${YELLOW}[WARN]${NC} $1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
}
|
||||
|
||||
# Validate required variables
|
||||
if [ -z "$SSH_HOST" ] || [ -z "$SSH_USER" ]; then
|
||||
log_error "SSH configuration missing for ${ENVIRONMENT}"
|
||||
log_error "Please set: ${ENVIRONMENT^^}_HOST and ${ENVIRONMENT^^}_USER"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# SSH command helper
|
||||
ssh_exec() {
|
||||
if [ -n "$SSH_KEY" ]; then
|
||||
ssh -i "$SSH_KEY" -o StrictHostKeyChecking=no "${SSH_USER}@${SSH_HOST}" "$@"
|
||||
else
|
||||
ssh -o StrictHostKeyChecking=no "${SSH_USER}@${SSH_HOST}" "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
# SCP command helper
|
||||
scp_copy() {
|
||||
if [ -n "$SSH_KEY" ]; then
|
||||
scp -i "$SSH_KEY" -o StrictHostKeyChecking=no "$@"
|
||||
else
|
||||
scp -o StrictHostKeyChecking=no "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
log_info "Starting deployment to ${ENVIRONMENT}..."
|
||||
log_info "Target: ${SSH_USER}@${SSH_HOST}"
|
||||
log_info "Service: ${SERVICE}"
|
||||
echo ""
|
||||
|
||||
# Step 1: Prepare deployment directory
|
||||
log_info "Preparing deployment directory..."
|
||||
ssh_exec << EOF
|
||||
mkdir -p ${DEPLOY_DIR}
|
||||
mkdir -p ${DEPLOY_DIR}/logs
|
||||
mkdir -p ${DEPLOY_DIR}/backups
|
||||
cd ${DEPLOY_DIR}
|
||||
EOF
|
||||
|
||||
# Step 2: Copy docker-compose file
|
||||
log_info "Copying docker-compose configuration..."
|
||||
scp_copy "${COMPOSE_FILE}" "${SSH_USER}@${SSH_HOST}:${DEPLOY_DIR}/docker-compose.yml"
|
||||
|
||||
# Step 3: Copy environment file if exists
|
||||
if [ -f ".env.${ENVIRONMENT}" ]; then
|
||||
log_info "Copying environment configuration..."
|
||||
scp_copy ".env.${ENVIRONMENT}" "${SSH_USER}@${SSH_HOST}:${DEPLOY_DIR}/.env"
|
||||
else
|
||||
log_warn "No .env.${ENVIRONMENT} file found, using existing environment"
|
||||
fi
|
||||
|
||||
# Step 4: Pull latest images
|
||||
log_info "Pulling latest Docker images..."
|
||||
ssh_exec << EOF
|
||||
cd ${DEPLOY_DIR}
|
||||
docker compose pull ${SERVICE}
|
||||
EOF
|
||||
|
||||
# Step 5: Run migrations if needed
|
||||
if [ "$SERVICE" == "all" ] || [ "$SERVICE" == "mana-core-auth" ]; then
|
||||
log_info "Running database migrations..."
|
||||
ssh_exec << EOF
|
||||
cd ${DEPLOY_DIR}
|
||||
docker compose run --rm mana-core-auth pnpm run db:migrate || echo "Migrations completed or skipped"
|
||||
EOF
|
||||
fi
|
||||
|
||||
# Step 6: Deploy services
|
||||
log_info "Deploying services..."
|
||||
if [ "$SERVICE" == "all" ]; then
|
||||
# Zero-downtime rolling update for all services
|
||||
ssh_exec << 'EOF'
|
||||
cd ${DEPLOY_DIR}
|
||||
|
||||
SERVICES=$(docker compose config --services)
|
||||
|
||||
for service in $SERVICES; do
|
||||
echo "Deploying $service..."
|
||||
|
||||
# Scale up with new version
|
||||
docker compose up -d --no-deps --scale $service=2 $service
|
||||
sleep 15
|
||||
|
||||
# Scale down to single instance
|
||||
docker compose up -d --no-deps --scale $service=1 $service
|
||||
sleep 5
|
||||
done
|
||||
|
||||
# Cleanup old images
|
||||
docker image prune -f
|
||||
EOF
|
||||
else
|
||||
# Deploy single service
|
||||
ssh_exec << EOF
|
||||
cd ${DEPLOY_DIR}
|
||||
docker compose up -d --no-deps ${SERVICE}
|
||||
sleep 10
|
||||
EOF
|
||||
fi
|
||||
|
||||
# Step 7: Health checks
|
||||
log_info "Running health checks..."
|
||||
HEALTH_ENDPOINTS=(
|
||||
"mana-core-auth:3001:/api/v1/health"
|
||||
"maerchenzauber-backend:3002:/health"
|
||||
"chat-backend:3002:/api/health"
|
||||
)
|
||||
|
||||
FAILED_CHECKS=0
|
||||
|
||||
for endpoint in "${HEALTH_ENDPOINTS[@]}"; do
|
||||
IFS=':' read -r service port path <<< "$endpoint"
|
||||
|
||||
log_info "Checking health of ${service}..."
|
||||
|
||||
if ssh_exec << EOF
|
||||
HEALTH=\$(docker compose -f ${DEPLOY_DIR}/docker-compose.yml exec -T ${service} wget -q -O - http://localhost:${port}${path} 2>/dev/null || echo "FAILED")
|
||||
|
||||
if [[ "\$HEALTH" == *"FAILED"* ]]; then
|
||||
echo "Health check failed for ${service}"
|
||||
exit 1
|
||||
else
|
||||
echo "Health check passed for ${service}"
|
||||
exit 0
|
||||
fi
|
||||
EOF
|
||||
then
|
||||
log_info "✅ ${service} is healthy"
|
||||
else
|
||||
log_error "❌ ${service} health check failed"
|
||||
((FAILED_CHECKS++))
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
|
||||
# Step 8: Display service status
|
||||
log_info "Current service status:"
|
||||
ssh_exec << EOF
|
||||
cd ${DEPLOY_DIR}
|
||||
docker compose ps
|
||||
EOF
|
||||
|
||||
echo ""
|
||||
|
||||
# Final result
|
||||
if [ $FAILED_CHECKS -eq 0 ]; then
|
||||
log_info "Deployment to ${ENVIRONMENT} completed successfully! ✅"
|
||||
exit 0
|
||||
else
|
||||
log_error "Deployment completed with ${FAILED_CHECKS} failed health checks"
|
||||
log_warn "Please check service logs with: ssh ${SSH_USER}@${SSH_HOST} 'cd ${DEPLOY_DIR} && docker compose logs'"
|
||||
exit 1
|
||||
fi
|
||||
|
|
@ -1,88 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Health check script for deployed services
|
||||
# Usage: ./health-check.sh [environment]
|
||||
# Example: ./health-check.sh staging
|
||||
# Example: ./health-check.sh production
|
||||
|
||||
set -e
|
||||
|
||||
# Colors
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
ENVIRONMENT=${1:-"staging"}
|
||||
|
||||
# Environment-specific configuration
|
||||
if [ "$ENVIRONMENT" == "production" ]; then
|
||||
BASE_URL=${PRODUCTION_API_URL:-"https://api.mana.how"}
|
||||
else
|
||||
BASE_URL=${STAGING_API_URL:-"https://staging.mana.how"}
|
||||
fi
|
||||
|
||||
log_info() {
|
||||
echo -e "${GREEN}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
log_warn() {
|
||||
echo -e "${YELLOW}[WARN]${NC} $1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
}
|
||||
|
||||
# Health check endpoints
|
||||
declare -A ENDPOINTS=(
|
||||
["Mana Core Auth"]="/api/v1/health"
|
||||
["Maerchenzauber Backend"]="/health"
|
||||
["Chat Backend"]="/api/health"
|
||||
)
|
||||
|
||||
# Counter for failed checks
|
||||
FAILED=0
|
||||
TOTAL=0
|
||||
|
||||
log_info "Running health checks for ${ENVIRONMENT}..."
|
||||
log_info "Base URL: ${BASE_URL}"
|
||||
echo ""
|
||||
|
||||
# Check each endpoint
|
||||
for service in "${!ENDPOINTS[@]}"; do
|
||||
endpoint="${ENDPOINTS[$service]}"
|
||||
url="${BASE_URL}${endpoint}"
|
||||
|
||||
((TOTAL++))
|
||||
|
||||
log_info "Checking ${service}..."
|
||||
|
||||
# Make HTTP request
|
||||
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" "${url}" -m 10 || echo "000")
|
||||
|
||||
if [ "$HTTP_CODE" == "200" ]; then
|
||||
log_info "✅ ${service}: OK (HTTP ${HTTP_CODE})"
|
||||
else
|
||||
log_error "❌ ${service}: FAILED (HTTP ${HTTP_CODE})"
|
||||
((FAILED++))
|
||||
fi
|
||||
|
||||
echo ""
|
||||
done
|
||||
|
||||
# Summary
|
||||
echo "=========================================="
|
||||
log_info "Health Check Summary:"
|
||||
echo " Total checks: ${TOTAL}"
|
||||
echo " Passed: $((TOTAL - FAILED))"
|
||||
echo " Failed: ${FAILED}"
|
||||
echo "=========================================="
|
||||
|
||||
if [ $FAILED -eq 0 ]; then
|
||||
log_info "All health checks passed! ✅"
|
||||
exit 0
|
||||
else
|
||||
log_error "${FAILED} health check(s) failed ❌"
|
||||
exit 1
|
||||
fi
|
||||
|
|
@ -1,116 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Database migration script for Supabase projects
|
||||
# Usage: ./migrate-db.sh [project] [environment]
|
||||
# Example: ./migrate-db.sh chat staging
|
||||
# Example: ./migrate-db.sh mana-core-auth production
|
||||
|
||||
set -e
|
||||
|
||||
# Colors
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
PROJECT=${1}
|
||||
ENVIRONMENT=${2:-"staging"}
|
||||
|
||||
log_info() {
|
||||
echo -e "${GREEN}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
log_warn() {
|
||||
echo -e "${YELLOW}[WARN]${NC} $1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
}
|
||||
|
||||
# Validate input
|
||||
if [ -z "$PROJECT" ]; then
|
||||
log_error "Project name is required"
|
||||
echo "Usage: ./migrate-db.sh [project] [environment]"
|
||||
echo "Available projects: chat, maerchenzauber, manadeck, memoro, picture, nutriphi, news, mana-core-auth"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_info "Running database migrations for ${PROJECT} (${ENVIRONMENT})..."
|
||||
|
||||
# Set Supabase environment variables based on project and environment
|
||||
case "$PROJECT" in
|
||||
"chat")
|
||||
if [ "$ENVIRONMENT" == "production" ]; then
|
||||
SUPABASE_URL=${CHAT_SUPABASE_URL}
|
||||
SUPABASE_SERVICE_KEY=${CHAT_SUPABASE_SERVICE_KEY}
|
||||
else
|
||||
SUPABASE_URL=${STAGING_CHAT_SUPABASE_URL}
|
||||
SUPABASE_SERVICE_KEY=${STAGING_CHAT_SUPABASE_SERVICE_KEY}
|
||||
fi
|
||||
MIGRATION_DIR="apps/chat/supabase/migrations"
|
||||
;;
|
||||
"maerchenzauber")
|
||||
if [ "$ENVIRONMENT" == "production" ]; then
|
||||
SUPABASE_URL=${MAERCHENZAUBER_SUPABASE_URL}
|
||||
SUPABASE_SERVICE_KEY=${MAERCHENZAUBER_SUPABASE_SERVICE_KEY}
|
||||
else
|
||||
SUPABASE_URL=${STAGING_MAERCHENZAUBER_SUPABASE_URL}
|
||||
SUPABASE_SERVICE_KEY=${STAGING_MAERCHENZAUBER_SUPABASE_SERVICE_KEY}
|
||||
fi
|
||||
MIGRATION_DIR="apps/maerchenzauber/supabase/migrations"
|
||||
;;
|
||||
"mana-core-auth")
|
||||
if [ "$ENVIRONMENT" == "production" ]; then
|
||||
DATABASE_URL=${PRODUCTION_AUTH_DATABASE_URL}
|
||||
else
|
||||
DATABASE_URL=${STAGING_AUTH_DATABASE_URL}
|
||||
fi
|
||||
MIGRATION_DIR="services/mana-core-auth/src/db/migrations"
|
||||
|
||||
# Use Drizzle for mana-core-auth
|
||||
log_info "Running Drizzle migrations for mana-core-auth..."
|
||||
cd services/mana-core-auth
|
||||
pnpm run db:migrate
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
log_error "Unknown project: $PROJECT"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# Check if migration directory exists
|
||||
if [ ! -d "$MIGRATION_DIR" ]; then
|
||||
log_warn "No migrations found for ${PROJECT}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Check for Supabase CLI
|
||||
if ! command -v supabase &> /dev/null; then
|
||||
log_error "Supabase CLI is not installed"
|
||||
log_info "Install it with: npm install -g supabase"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Link to remote project
|
||||
log_info "Linking to Supabase project..."
|
||||
supabase link --project-ref $(echo $SUPABASE_URL | sed 's|https://||' | sed 's|.supabase.co||')
|
||||
|
||||
# Run migrations
|
||||
log_info "Applying migrations from ${MIGRATION_DIR}..."
|
||||
cd $MIGRATION_DIR
|
||||
|
||||
# List pending migrations
|
||||
log_info "Pending migrations:"
|
||||
ls -1 *.sql 2>/dev/null || log_info "No SQL migrations found"
|
||||
|
||||
# Apply migrations using Supabase CLI
|
||||
for migration in *.sql; do
|
||||
if [ -f "$migration" ]; then
|
||||
log_info "Applying migration: $migration"
|
||||
supabase db push
|
||||
fi
|
||||
done
|
||||
|
||||
log_info "Database migrations completed successfully! ✅"
|
||||
|
|
@ -1,213 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Rollback script for emergency deployment rollback
|
||||
# Usage: ./rollback.sh [environment] [service]
|
||||
# Example: ./rollback.sh production all
|
||||
# Example: ./rollback.sh staging chat-backend
|
||||
|
||||
set -e
|
||||
|
||||
# Colors
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
ENVIRONMENT=${1:-"staging"}
|
||||
SERVICE=${2:-"all"}
|
||||
|
||||
# Environment-specific variables
|
||||
if [ "$ENVIRONMENT" == "production" ]; then
|
||||
SSH_HOST=${PRODUCTION_HOST}
|
||||
SSH_USER=${PRODUCTION_USER}
|
||||
SSH_KEY=${PRODUCTION_SSH_KEY}
|
||||
DEPLOY_DIR="~/manacore-production"
|
||||
else
|
||||
SSH_HOST=${STAGING_HOST}
|
||||
SSH_USER=${STAGING_USER}
|
||||
SSH_KEY=${STAGING_SSH_KEY}
|
||||
DEPLOY_DIR="~/manacore-staging"
|
||||
fi
|
||||
|
||||
log_info() {
|
||||
echo -e "${GREEN}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
log_warn() {
|
||||
echo -e "${YELLOW}[WARN]${NC} $1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
}
|
||||
|
||||
# Validate required variables
|
||||
if [ -z "$SSH_HOST" ] || [ -z "$SSH_USER" ]; then
|
||||
log_error "SSH configuration missing for ${ENVIRONMENT}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# SSH command helper
|
||||
ssh_exec() {
|
||||
if [ -n "$SSH_KEY" ]; then
|
||||
ssh -i "$SSH_KEY" -o StrictHostKeyChecking=no "${SSH_USER}@${SSH_HOST}" "$@"
|
||||
else
|
||||
ssh -o StrictHostKeyChecking=no "${SSH_USER}@${SSH_HOST}" "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
log_warn "⚠️ ROLLBACK INITIATED ⚠️"
|
||||
log_info "Environment: ${ENVIRONMENT}"
|
||||
log_info "Service: ${SERVICE}"
|
||||
echo ""
|
||||
|
||||
# Confirm rollback
|
||||
read -p "Are you sure you want to rollback? (yes/no): " confirm
|
||||
if [ "$confirm" != "yes" ]; then
|
||||
log_info "Rollback cancelled"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo ""
|
||||
log_info "Starting rollback process..."
|
||||
|
||||
# Step 1: Check for previous deployment backup
|
||||
log_info "Checking for previous deployment backup..."
|
||||
ssh_exec << EOF
|
||||
cd ${DEPLOY_DIR}
|
||||
|
||||
if [ ! -d "backups" ] || [ -z "\$(ls -A backups)" ]; then
|
||||
echo "ERROR: No backups found!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Get latest backup
|
||||
LATEST_BACKUP=\$(ls -t backups | head -1)
|
||||
echo "Latest backup found: \$LATEST_BACKUP"
|
||||
|
||||
cd backups/\$LATEST_BACKUP
|
||||
|
||||
# Verify backup contents
|
||||
if [ ! -f "docker-compose.yml" ]; then
|
||||
echo "ERROR: Backup incomplete - missing docker-compose.yml"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Backup validated"
|
||||
EOF
|
||||
|
||||
# Step 2: Stop current services
|
||||
log_info "Stopping current services..."
|
||||
ssh_exec << EOF
|
||||
cd ${DEPLOY_DIR}
|
||||
docker compose stop ${SERVICE}
|
||||
EOF
|
||||
|
||||
# Step 3: Restore from backup
|
||||
log_info "Restoring from backup..."
|
||||
ssh_exec << EOF
|
||||
cd ${DEPLOY_DIR}
|
||||
|
||||
LATEST_BACKUP=\$(ls -t backups | head -1)
|
||||
|
||||
# Restore docker-compose file
|
||||
cp backups/\$LATEST_BACKUP/docker-compose.yml ./docker-compose.yml
|
||||
|
||||
# Restore environment file if exists
|
||||
if [ -f "backups/\$LATEST_BACKUP/.env.backup" ]; then
|
||||
cp backups/\$LATEST_BACKUP/.env.backup ./.env
|
||||
fi
|
||||
|
||||
echo "Files restored from backup: \$LATEST_BACKUP"
|
||||
EOF
|
||||
|
||||
# Step 4: Restore database if service is auth
|
||||
if [ "$SERVICE" == "all" ] || [ "$SERVICE" == "mana-core-auth" ]; then
|
||||
log_info "Restoring database..."
|
||||
ssh_exec << EOF
|
||||
cd ${DEPLOY_DIR}
|
||||
|
||||
LATEST_BACKUP=\$(ls -t backups | head -1)
|
||||
|
||||
if [ -f "backups/\$LATEST_BACKUP/postgres_backup.sql" ]; then
|
||||
# Restore PostgreSQL backup
|
||||
docker compose exec -T postgres psql -U \$POSTGRES_USER < backups/\$LATEST_BACKUP/postgres_backup.sql
|
||||
echo "Database restored"
|
||||
else
|
||||
echo "WARNING: No database backup found"
|
||||
fi
|
||||
EOF
|
||||
fi
|
||||
|
||||
# Step 5: Start services with previous images
|
||||
log_info "Starting services with previous configuration..."
|
||||
ssh_exec << EOF
|
||||
cd ${DEPLOY_DIR}
|
||||
|
||||
# Get image tags from backup
|
||||
LATEST_BACKUP=\$(ls -t backups | head -1)
|
||||
|
||||
if [ -f "backups/\$LATEST_BACKUP/deployment_images.txt" ]; then
|
||||
echo "Previous deployment images:"
|
||||
cat backups/\$LATEST_BACKUP/deployment_images.txt
|
||||
fi
|
||||
|
||||
# Start services
|
||||
docker compose up -d ${SERVICE}
|
||||
|
||||
# Wait for services to start
|
||||
sleep 20
|
||||
EOF
|
||||
|
||||
# Step 6: Health checks
|
||||
log_info "Running health checks after rollback..."
|
||||
|
||||
HEALTH_ENDPOINTS=(
|
||||
"mana-core-auth:3001:/api/v1/health"
|
||||
"maerchenzauber-backend:3002:/health"
|
||||
"chat-backend:3002:/api/health"
|
||||
)
|
||||
|
||||
FAILED_CHECKS=0
|
||||
|
||||
for endpoint in "${HEALTH_ENDPOINTS[@]}"; do
|
||||
IFS=':' read -r service port path <<< "$endpoint"
|
||||
|
||||
if ssh_exec << EOF
|
||||
HEALTH=\$(docker compose -f ${DEPLOY_DIR}/docker-compose.yml exec -T ${service} wget -q -O - http://localhost:${port}${path} 2>/dev/null || echo "FAILED")
|
||||
|
||||
if [[ "\$HEALTH" == *"FAILED"* ]]; then
|
||||
exit 1
|
||||
else
|
||||
exit 0
|
||||
fi
|
||||
EOF
|
||||
then
|
||||
log_info "✅ ${service} is healthy"
|
||||
else
|
||||
log_warn "⚠️ ${service} health check failed"
|
||||
((FAILED_CHECKS++))
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
|
||||
# Step 7: Display service status
|
||||
log_info "Current service status:"
|
||||
ssh_exec << EOF
|
||||
cd ${DEPLOY_DIR}
|
||||
docker compose ps
|
||||
EOF
|
||||
|
||||
echo ""
|
||||
|
||||
# Final result
|
||||
if [ $FAILED_CHECKS -eq 0 ]; then
|
||||
log_info "Rollback completed successfully! ✅"
|
||||
log_info "Services have been restored to previous version"
|
||||
exit 0
|
||||
else
|
||||
log_error "Rollback completed with ${FAILED_CHECKS} failed health checks"
|
||||
log_warn "Manual intervention may be required"
|
||||
exit 1
|
||||
fi
|
||||
|
|
@ -1,124 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Generate Staging Secrets for GitHub
|
||||
# Run this script and copy the output to GitHub Secrets
|
||||
|
||||
set -e
|
||||
|
||||
echo "================================================"
|
||||
echo " STAGING SECRETS GENERATOR"
|
||||
echo "================================================"
|
||||
echo ""
|
||||
echo "Copy each value below to GitHub Settings → Secrets and variables → Actions"
|
||||
echo ""
|
||||
echo "Note: Configuration values (host, ports, etc.) are now hardcoded in the workflow"
|
||||
echo "Only sensitive values (passwords, keys) need to be added as secrets"
|
||||
echo ""
|
||||
echo "================================================"
|
||||
echo ""
|
||||
|
||||
# Generate secure random passwords
|
||||
POSTGRES_PASSWORD=$(openssl rand -base64 32 | tr -d "=+/" | cut -c1-32)
|
||||
REDIS_PASSWORD=$(openssl rand -base64 32 | tr -d "=+/" | cut -c1-32)
|
||||
JWT_SECRET=$(openssl rand -base64 64 | tr -d "=+/" | cut -c1-64)
|
||||
|
||||
# Generate Ed25519 key pair for JWT
|
||||
TEMP_KEY_DIR=$(mktemp -d)
|
||||
ssh-keygen -t ed25519 -f "$TEMP_KEY_DIR/jwt_key" -N "" -C "manacore-staging-jwt" > /dev/null 2>&1
|
||||
|
||||
# Convert SSH keys to raw format for JWT
|
||||
PRIVATE_KEY=$(cat "$TEMP_KEY_DIR/jwt_key" | grep -v "BEGIN" | grep -v "END" | tr -d '\n')
|
||||
PUBLIC_KEY=$(ssh-keygen -e -m PKCS8 -f "$TEMP_KEY_DIR/jwt_key.pub" 2>/dev/null | grep -v "BEGIN" | grep -v "END" | tr -d '\n' || cat "$TEMP_KEY_DIR/jwt_key.pub" | awk '{print $2}')
|
||||
|
||||
# Clean up temp files
|
||||
rm -rf "$TEMP_KEY_DIR"
|
||||
|
||||
# Output all secrets in GitHub format
|
||||
echo "# ============================================"
|
||||
echo "# DATABASE SECRETS (2 secrets)"
|
||||
echo "# ============================================"
|
||||
echo ""
|
||||
echo "STAGING_POSTGRES_PASSWORD"
|
||||
echo "$POSTGRES_PASSWORD"
|
||||
echo ""
|
||||
|
||||
echo "# ============================================"
|
||||
echo "# REDIS SECRETS (1 secret)"
|
||||
echo "# ============================================"
|
||||
echo ""
|
||||
echo "STAGING_REDIS_PASSWORD"
|
||||
echo "$REDIS_PASSWORD"
|
||||
echo ""
|
||||
|
||||
echo "# ============================================"
|
||||
echo "# MANA CORE AUTH SECRETS (3 secrets)"
|
||||
echo "# ============================================"
|
||||
echo ""
|
||||
echo "STAGING_JWT_SECRET"
|
||||
echo "$JWT_SECRET"
|
||||
echo ""
|
||||
echo "STAGING_JWT_PUBLIC_KEY"
|
||||
echo "$PUBLIC_KEY"
|
||||
echo ""
|
||||
echo "STAGING_JWT_PRIVATE_KEY"
|
||||
echo "$PRIVATE_KEY"
|
||||
echo ""
|
||||
|
||||
echo "# ============================================"
|
||||
echo "# SUPABASE SECRETS (Fill these manually - 3 secrets)"
|
||||
echo "# ============================================"
|
||||
echo ""
|
||||
echo "STAGING_SUPABASE_URL"
|
||||
echo "https://YOUR_PROJECT.supabase.co"
|
||||
echo ""
|
||||
echo "STAGING_SUPABASE_ANON_KEY"
|
||||
echo "YOUR_SUPABASE_ANON_KEY_HERE"
|
||||
echo ""
|
||||
echo "STAGING_SUPABASE_SERVICE_ROLE_KEY"
|
||||
echo "YOUR_SUPABASE_SERVICE_ROLE_KEY_HERE"
|
||||
echo ""
|
||||
|
||||
echo "# ============================================"
|
||||
echo "# AZURE OPENAI SECRETS (Fill these manually - 2 secrets)"
|
||||
echo "# ============================================"
|
||||
echo ""
|
||||
echo "STAGING_AZURE_OPENAI_ENDPOINT"
|
||||
echo "https://YOUR_RESOURCE.openai.azure.com/"
|
||||
echo ""
|
||||
echo "STAGING_AZURE_OPENAI_API_KEY"
|
||||
echo "YOUR_AZURE_OPENAI_API_KEY_HERE"
|
||||
echo ""
|
||||
|
||||
echo "# ============================================"
|
||||
echo "# SSH DEPLOYMENT SECRETS (Fill these manually - 1 secret)"
|
||||
echo "# ============================================"
|
||||
echo ""
|
||||
echo "STAGING_SSH_KEY"
|
||||
echo "Run: cat ~/.ssh/hetzner_deploy_key"
|
||||
echo "(Copy the ENTIRE output including -----BEGIN and -----END lines)"
|
||||
echo ""
|
||||
|
||||
echo "================================================"
|
||||
echo " SUMMARY"
|
||||
echo "================================================"
|
||||
echo ""
|
||||
echo "Total secrets to add: 12"
|
||||
echo " - Auto-generated: 6 (passwords, JWT keys)"
|
||||
echo " - Manual: 6 (Supabase, Azure, SSH key)"
|
||||
echo ""
|
||||
echo "The following are now HARDCODED in the workflow:"
|
||||
echo " - POSTGRES_HOST, POSTGRES_PORT, POSTGRES_DB, POSTGRES_USER"
|
||||
echo " - REDIS_HOST, REDIS_PORT"
|
||||
echo " - MANA_SERVICE_URL"
|
||||
echo " - STAGING_HOST (46.224.108.214)"
|
||||
echo " - STAGING_USER (deploy)"
|
||||
echo ""
|
||||
echo "================================================"
|
||||
echo ""
|
||||
echo "Next steps:"
|
||||
echo "1. Go to: https://github.com/YOUR_ORG/manacore-monorepo/settings/secrets/actions"
|
||||
echo "2. Click 'New repository secret' for each value above"
|
||||
echo "3. Copy the secret name (e.g., STAGING_POSTGRES_PASSWORD)"
|
||||
echo "4. Copy the secret value (the line below the name)"
|
||||
echo "5. Fill in Supabase, Azure, and SSH key values manually"
|
||||
echo ""
|
||||
Loading…
Add table
Add a link
Reference in a new issue