AkurAI Build
Menu

Public repository / 1c4949c9fc865519b48f48b69196534c6a80e8b4

AkurAI-Mail / deploy.sh

Latest change b7f6b07335df8810394a514c92fa3f27657e3319 - hook: push new-mail notifications to pi-bun on delivery (drop pi-bun 5-min poll) by Ólafur Búi Ólafsson

#!/usr/bin/env bash
# Deploy rules of conduct:
# - Read AGENTS.md and canonical Notes/docs before changing or deploying.
# - Never print, commit, or copy secrets; use passvault/env files only.
# - Preserve env files, service users, user data, and databases; snapshot state before risky swaps.
# - Verify ports, DNS, TLS, and systemd unit names before changing routes or services.
# - Use managed services only (systemd/pm2); no nohup, background shells, or ad hoc daemons.
# - Run gates and health checks; if deploy fails, stop and roll back rather than improvising.
# - Keep deploy behavior unchanged unless the task explicitly asks for deploy logic changes.
set -euo pipefail

# ---------------------------------------------------------------------------
# AkurAI Mail UI — build locally, deploy artifacts to AWS VM
# ---------------------------------------------------------------------------

APP_NAME="akurai-mail-ui"
SSH_HOST="${AKURAI_MAIL_SSH:-akurai-mail}"
DEPLOY_DIR="/opt/${APP_NAME}"
SERVICE="${APP_NAME}"

VERSION="$(cat VERSION | tr -d '\n')"
RELEASE_ID="$(date -u +%Y%m%dT%H%M%SZ)-$(git rev-parse --short HEAD 2>/dev/null || echo nogit)"
STAGING_DIR="${PWD}/.deploy-staging/${RELEASE_ID}"

log()  { echo "[deploy] $*"; }
step() { echo; echo "── $* ──"; }

remote() { ssh "${SSH_HOST}" "$@"; }

# ---------------------------------------------------------------------------
# Parse
# ---------------------------------------------------------------------------
COMMAND="${1:-prod}"
case "${COMMAND}" in
  status)
    git status --short --branch
    remote "sudo systemctl status ${SERVICE} --no-pager" || true
    exit 0
    ;;
  --help|-h|help)
    echo "Usage: deploy.sh [prod|status|help]"
    exit 0
    ;;
esac

# ---------------------------------------------------------------------------
# Step 1: Install + build locally
# ---------------------------------------------------------------------------
step "1/5  Local build"
bun install --frozen-lockfile 2>&1 || bun install
bun run build
log "Build complete"

# ---------------------------------------------------------------------------
# Step 2: Package artifacts
# ---------------------------------------------------------------------------
step "2/5  Package"
mkdir -p "${STAGING_DIR}"
TARBALL="${STAGING_DIR}/${APP_NAME}-${RELEASE_ID}.tar.gz"
ARCHIVE_FILES=(
  build/
  package.json
  bun.lock
  scripts/
  backup.sh
  rollback.sh
  VERSION
)
[[ -f CHANGELOG.md ]] && ARCHIVE_FILES+=(CHANGELOG.md)
tar czf "${TARBALL}" "${ARCHIVE_FILES[@]}"
log "Tarball: $(du -sh "${TARBALL}" | cut -f1)"

# ---------------------------------------------------------------------------
# Step 3: Upload
# ---------------------------------------------------------------------------
step "3/5  Upload to ${SSH_HOST}"
remote "mkdir -p /tmp/akurai-mail-deploy"
scp -q "${TARBALL}" "${SSH_HOST}:/tmp/akurai-mail-deploy/"

# ---------------------------------------------------------------------------
# Step 4: Remote install
# ---------------------------------------------------------------------------
step "4/5  Remote install"
ARCHIVE_BASENAME="$(basename "${TARBALL}")"
remote "sudo bash -s" <<INSTALL
set -euo pipefail

# Backup current
if [ -d ${DEPLOY_DIR}/build ]; then
  BACKUP_DIR="/opt/${APP_NAME}-backups/${RELEASE_ID}"
  mkdir -p "\${BACKUP_DIR}"
  tar czf "\${BACKUP_DIR}/app.tar.gz" -C ${DEPLOY_DIR} build/ package.json VERSION 2>/dev/null || true
  echo "  [backup] \${BACKUP_DIR}"
fi

# Extract new release (overwrite build/ and support files)
tar xzf /tmp/akurai-mail-deploy/${ARCHIVE_BASENAME} -C ${DEPLOY_DIR}
mkdir -p ${DEPLOY_DIR}/app
ln -sfn ../build ${DEPLOY_DIR}/app/frontend

# Install production runtime deps
cd ${DEPLOY_DIR}
/home/ubuntu/.bun/bin/bun install --frozen-lockfile --production 2>/dev/null || /home/ubuntu/.bun/bin/bun install --production

# Install helper scripts
install -m 755 scripts/akurai-mail-server /usr/local/sbin/akurai-mail-server
install -m 755 backup.sh /usr/local/sbin/akurai-mail-backup
install -m 755 rollback.sh /usr/local/sbin/akurai-mail-rollback

# Delivery-hook watcher unit + its env (URL only; token via akurai-ec2 secret-sync)
install -m 644 scripts/akurai-mail-hook.service /etc/systemd/system/akurai-mail-hook.service
if ! grep -q '^AKURAI_MAIL_PIBUN_URL=' /etc/akurai-mail-hook.env 2>/dev/null; then
  touch /etc/akurai-mail-hook.env
  chmod 600 /etc/akurai-mail-hook.env
  printf 'AKURAI_MAIL_PIBUN_URL=http://100.88.0.9:4173/api/ingest-mail\n' >> /etc/akurai-mail-hook.env
fi

# Ensure state file
install -d -o ubuntu -g ubuntu /var/lib/akurai-mail
if [ ! -s /var/lib/akurai-mail/state.json ]; then
  printf '{"domain":"olibuijr.com","hostname":"mail.olibuijr.com","publicIp":"3.94.46.219","users":[],"aliases":[],"events":[],"metricsHistory":[]}\n' > /var/lib/akurai-mail/state.json
fi
chown ubuntu:ubuntu /var/lib/akurai-mail/state.json

# Restart
systemctl daemon-reload
systemctl restart ${SERVICE}
systemctl enable akurai-mail-hook.service
systemctl restart akurai-mail-hook.service

# Cleanup
rm -rf /tmp/akurai-mail-deploy

# Prune old backups (keep 10)
ls -dt /opt/${APP_NAME}-backups/*/ 2>/dev/null | tail -n +11 | xargs -r rm -rf

echo "  [done] ${APP_NAME} ${VERSION} installed"
INSTALL

# ---------------------------------------------------------------------------
# Step 5: Healthcheck
# ---------------------------------------------------------------------------
step "5/5  Healthcheck"
sleep 2

if curl -fsS -o /dev/null -w '%{http_code}' https://mail.olibuijr.com/webmail/login | grep -q 200; then
  log "Healthcheck passed"
else
  echo "ERROR: healthcheck failed"
  echo "Check: ssh ${SSH_HOST} 'sudo journalctl -u ${SERVICE} -n 50'"
  exit 1
fi

if remote "systemctl is-active akurai-mail-hook.service" | grep -q '^active$'; then
  log "Delivery hook active"
else
  log "WARNING: akurai-mail-hook.service is not active — check: ssh ${SSH_HOST} 'sudo journalctl -u akurai-mail-hook.service -n 50'"
fi

rm -rf "${STAGING_DIR}"

echo
echo "════════════════════════════════════════════════════"
echo "  AkurAI Mail UI deployed"
echo "════════════════════════════════════════════════════"
echo "  Version  : ${VERSION}"
echo "  Release  : ${RELEASE_ID}"
echo "  Host     : ${SSH_HOST}"
echo "  Public   : https://mail.olibuijr.com"
echo "════════════════════════════════════════════════════"