Files
base/docker/backup.sh
iven 3772afd987 chore: 干净 ERP 基座 — 删除 health/ai/wechat 业务代码
删除内容:
- 前端: health/(67文件), ai/(2文件), Copilot, MediaPicker, 相关API/Store/Hook
- 后端: wechat_handler, wechat_service, wechat_user entity, analytics handler, ai_workflow_seed
- 配置: WechatConfig, AppConfig.wechat, AuthState wechat 字段
- 启动: 微信凭据检查块, ensure_ai_workflows() 调用
- 迁移: 新增 m20260613_000170_drop_wechat_users.rs
- 脚本: api_test_health_alert.py, api_test_mp.py, mpsync.sh/ps1
- E2E: health-data page, flows/ 目录

保留: erp-core/auth/workflow/message/config/plugin + 基座前端 + 通用组件
2026-06-13 00:32:50 +08:00

96 lines
3.5 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# PostgreSQL 自动备份脚本(含加密)
# 用法:
# 手动: ./docker/backup.sh
# 自动: 由 docker compose backup 服务每日 02:00 执行
#
# 加密方式(二选一):
# BACKUP_PASSPHRASE — 使用 openssl AES-256-CBC 对称加密(无额外依赖)
# GPG_RECIPIENT — 使用 GPG 非对称加密(需预置公钥)
set -euo pipefail
BACKUP_DIR="${BACKUP_DIR:-/backups}"
PG_HOST="${PGHOST:-postgres}"
PG_PORT="${PGPORT:-5432}"
PG_USER="${PGUSER:-erp}"
PG_DB="${PGDATABASE:-erp}"
KEEP_DAYS="${KEEP_DAYS:-7}"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
FILENAME="${PG_DB}_${TIMESTAMP}.sql.gz"
ENCRYPTED_FILENAME="${FILENAME}.enc"
FILEPATH="${BACKUP_DIR}/${FILENAME}"
ENCRYPTED_FILEPATH="${BACKUP_DIR}/${ENCRYPTED_FILENAME}"
mkdir -p "${BACKUP_DIR}"
echo "[$(date -Iseconds)] 开始备份 ${PG_DB}${FILEPATH}"
if pg_dump \
-h "${PG_HOST}" \
-p "${PG_PORT}" \
-U "${PG_USER}" \
-d "${PG_DB}" \
--format=plain \
--no-owner \
--no-privileges \
| gzip > "${FILEPATH}"; then
SIZE=$(du -h "${FILEPATH}" | cut -f1)
echo "[$(date -Iseconds)] 备份完成: ${FILENAME} (${SIZE})"
else
echo "[$(date -Iseconds)] 备份失败!" >&2
rm -f "${FILEPATH}"
exit 1
fi
# ── 加密备份 ──
if [ -n "${BACKUP_PASSPHRASE:-}" ]; then
echo "[$(date -Iseconds)] 使用 AES-256-CBC 加密备份..."
if openssl enc -aes-256-cbc -salt -pbkdf2 -pass "pass:${BACKUP_PASSPHRASE}" \
-in "${FILEPATH}" -out "${ENCRYPTED_FILEPATH}"; then
rm -f "${FILEPATH}"
ENC_SIZE=$(du -h "${ENCRYPTED_FILEPATH}" | cut -f1)
echo "[$(date -Iseconds)] 加密完成: ${ENCRYPTED_FILENAME} (${ENC_SIZE})"
else
echo "[$(date -Iseconds)] 加密失败!保留未加密备份" >&2
rm -f "${ENCRYPTED_FILEPATH}"
fi
elif [ -n "${GPG_RECIPIENT:-}" ]; then
echo "[$(date -Iseconds)] 使用 GPG 加密备份..."
if gpg --batch --yes --encrypt --recipient "${GPG_RECIPIENT}" "${FILEPATH}"; then
rm -f "${FILEPATH}"
ENC_SIZE=$(du -h "${ENCRYPTED_FILEPATH}" | cut -f1)
echo "[$(date -Iseconds)] 加密完成: ${ENCRYPTED_FILENAME} (${ENC_SIZE})"
else
echo "[$(date -Iseconds)] GPG 加密失败!保留未加密备份" >&2
rm -f "${FILEPATH}.gpg"
fi
else
echo "[$(date -Iseconds)] 警告: 未设置 BACKUP_PASSPHRASE 或 GPG_RECIPIENT备份未加密" >&2
fi
# ── 备份完整性校验 ──
LATEST_FILE=$(ls -t "${BACKUP_DIR}/${PG_DB}"_*.sql.gz* 2>/dev/null | head -1)
if [ -n "${LATEST_FILE}" ] && [ -f "${LATEST_FILE}" ]; then
if [[ "${LATEST_FILE}" == *.enc ]]; then
echo "[$(date -Iseconds)] 加密备份文件存在: $(basename "${LATEST_FILE}")"
elif gzip -t "${LATEST_FILE}" 2>/dev/null; then
echo "[$(date -Iseconds)] 备份完整性校验通过"
else
echo "[$(date -Iseconds)] 警告: 备份文件可能损坏: ${LATEST_FILE}" >&2
fi
fi
# ── 清理过期备份 ──
DELETED=$(find "${BACKUP_DIR}" -name "${PG_DB}_*.sql.gz*" -mtime +${KEEP_DAYS} -delete -print | wc -l)
if [ "${DELETED}" -gt 0 ]; then
echo "[$(date -Iseconds)] 已清理 ${DELETED} 个过期备份(>${KEEP_DAYS}天)"
fi
# ── 恢复指引 ──
echo ""
echo "恢复方法:"
echo " # 解密(如加密):"
echo " openssl enc -d -aes-256-cbc -pbkdf2 -pass pass:\$BACKUP_PASSPHRASE -in ${ENCRYPTED_FILEPATH} -out ${FILEPATH}"
echo " # 恢复:"
echo " gunzip -c ${FILEPATH} | psql -h \$PGHOST -U \$PGUSER -d \$PGDB"