#!/usr/bin/env bash set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" COMPOSE_FILE="docker-compose-multitenant.yml" # Directories INVOICE_ARCHIVE_DIR="${INVOICE_ARCHIVE_DIR:-/var/backups/invoice-archive}" FULL_BACKUP_DIR="${FULL_BACKUP_DIR:-/var/backups/inventarsystem}" LOG_DIR="$SCRIPT_DIR/logs" KEEP_DAYS="${INVOICE_KEEP_DAYS:-3650}" MODE="auto" BASE_NAME="" usage() { cat <&2; usage; exit 2 ;; esac done } ensure_directory() { mkdir -p "$INVOICE_ARCHIVE_DIR" mkdir -p "$FULL_BACKUP_DIR" } cleanup_old_archives() { if [[ -n "$KEEP_DAYS" ]]; then find "$INVOICE_ARCHIVE_DIR" -maxdepth 1 -type f -mtime +"$KEEP_DAYS" -print -delete 2>/dev/null || true fi # Cleanup old bundled backups (older than 30 days) find "$FULL_BACKUP_DIR" -maxdepth 1 -type f -name "full_backup_*.tar.gz" -mtime +30 -print -delete 2>/dev/null || true } docker_backup() { if ! command -v docker >/dev/null 2>&1; then return 1; fi local timestamp="$(date +'%Y-%m-%d_%H-%M-%S')" local staging_dir="/tmp/backup_stage_$timestamp" echo "[$(date +'%T')] Starting unified system backup..." mkdir -p "$staging_dir" # 1. MongoDB Dump (into staging) if docker compose -f "$COMPOSE_FILE" ps -q mongodb >/dev/null 2>&1; then echo "[$(date +'%T')] Dumping Database..." docker compose -f "$COMPOSE_FILE" exec -T mongodb mongodump --archive --gzip > "$staging_dir/db.archive.gz" fi # 2. Archive Assets (into staging) if [ -d "./Web/uploads" ]; then echo "[$(date +'%T')] Archiving assets..." tar -czf "$staging_dir/assets.tar.gz" -C . Web/uploads Web/thumbnails Web/previews 2>/dev/null || true fi # 3. Archive Logs (into staging) if [ -d "$LOG_DIR" ]; then echo "[$(date +'%T')] Archiving logs..." tar -czf "$staging_dir/logs.tar.gz" -C "$(dirname "$LOG_DIR")" "$(basename "$LOG_DIR")" fi # 4. Bundle everything into one file echo "[$(date +'%T')] Bundling archive..." tar -czf "$FULL_BACKUP_DIR/full_backup_$timestamp.tar.gz" -C "$staging_dir" . # 5. Cleanup staging rm -rf "$staging_dir" echo "[$(date +'%T')] Backup complete: $FULL_BACKUP_DIR/full_backup_$timestamp.tar.gz" return 0 } main() { parse_args "$@" ensure_directory case "$MODE" in auto|docker) if docker_backup; then cleanup_old_archives return 0 fi echo "Error: Docker backup failed." >&2 return 1 ;; *) echo "Error: unsupported mode '$MODE'" >&2 usage return 2 ;; esac } main "$@"