#!/usr/bin/env bash # Deploy script for CC Dashboard on optical-dev.oliver.solutions # Run ON the server: ssh optical-dev "cd /opt/cc-dashboard && bash deploy.sh" set -euo pipefail COMPOSE="docker compose -f /opt/cc-dashboard/docker-compose.yml" log() { echo "[$(date '+%H:%M:%S')] $*"; } die() { echo "[ERROR] $*" >&2; exit 1; } pass() { echo "[OK] $*"; } cd /opt/cc-dashboard || die "Cannot cd to /opt/cc-dashboard" # ── 1. Pull latest code ────────────────────────────────────────────────────── log "Pulling latest code from origin/main..." git fetch origin git reset --hard origin/main pass "Code updated: $(git log --oneline -1)" # ── 2. Rebuild app image ───────────────────────────────────────────────────── log "Building app image (Python deps + code)..." $COMPOSE build app pass "Image built." # ── 3. Restart app (alembic upgrade runs automatically in CMD) ─────────────── # DB container is NOT touched — data in pgdata volume is preserved. log "Restarting app container..." $COMPOSE up -d --no-deps app pass "Container restarted. Alembic migrations run on container start." # ── 4. Wait and verify ─────────────────────────────────────────────────────── log "Waiting for app to become healthy..." for i in $(seq 1 20); do if curl -fs http://localhost:8800/cc-dashboard/healthz > /dev/null 2>&1; then pass "Healthcheck OK after ${i}s." break fi sleep 1 if [[ $i -eq 20 ]]; then log "Healthcheck timeout — showing last 40 lines of logs:" $COMPOSE logs --tail=40 app die "App did not start in time." fi done # ── 5. Tail recent logs ────────────────────────────────────────────────────── log "Recent app logs:" $COMPOSE logs --tail=20 app log "Deploy complete. App at http://optical-dev.oliver.solutions:8800/cc-dashboard/"