backup_nexus 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +7 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.md +82 -0
  5. data/Rakefile +10 -0
  6. data/app/controllers/backup_nexus/application_controller.rb +31 -0
  7. data/app/controllers/backup_nexus/backup_controller.rb +119 -0
  8. data/app/helpers/backup_nexus/application_helper.rb +51 -0
  9. data/app/jobs/backup_nexus/backup_job.rb +18 -0
  10. data/app/models/backup_nexus/backup.rb +107 -0
  11. data/app/models/backup_nexus/backup_config.rb +189 -0
  12. data/app/services/backup_nexus/backup_runner.rb +62 -0
  13. data/app/services/backup_nexus/backup_service.rb +817 -0
  14. data/app/views/backup_nexus/backup/_form.html.erb +334 -0
  15. data/app/views/backup_nexus/backup/config_history.html.erb +67 -0
  16. data/app/views/backup_nexus/backup/edit.html.erb +15 -0
  17. data/app/views/backup_nexus/backup/history.html.erb +75 -0
  18. data/app/views/backup_nexus/backup/index.html.erb +112 -0
  19. data/app/views/backup_nexus/backup/new.html.erb +15 -0
  20. data/backup_nexus.gemspec +30 -0
  21. data/config/routes.rb +15 -0
  22. data/db/seeds/backup_configs_safe.rb +61 -0
  23. data/lib/backup_nexus/base_record.rb +7 -0
  24. data/lib/backup_nexus/configuration.rb +19 -0
  25. data/lib/backup_nexus/engine.rb +51 -0
  26. data/lib/backup_nexus/version.rb +3 -0
  27. data/lib/backup_nexus.rb +26 -0
  28. data/lib/generators/backup_nexus/backup_generator.rb +70 -0
  29. data/lib/generators/backup_nexus/install_generator.rb +27 -0
  30. data/lib/generators/backup_nexus/templates/backup/backup/backup_helper.sh +152 -0
  31. data/lib/generators/backup_nexus/templates/backup/backup/config.rb +27 -0
  32. data/lib/generators/backup_nexus/templates/backup/backup/models/daily_backup.rb +24 -0
  33. data/lib/generators/backup_nexus/templates/backup/backup/models/full_backup.rb +35 -0
  34. data/lib/generators/backup_nexus/templates/backup/backup/models/sync_backup.rb +43 -0
  35. data/lib/generators/backup_nexus/templates/backup/backup/mysql-config/db_config.cnf +15 -0
  36. data/lib/generators/backup_nexus/templates/backup/backup/schedule.rb +28 -0
  37. data/lib/generators/backup_nexus/templates/migration.rb +105 -0
  38. data/lib/tasks/backup_nexus.rake +81 -0
  39. metadata +138 -0
data/config/routes.rb ADDED
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ BackupNexus::Engine.routes.draw do
4
+ get "backup", to: "backup#index", as: :backup
5
+ get "backup/new", to: "backup#new", as: :new_backup
6
+ post "backup", to: "backup#create"
7
+ get "backup/history", to: "backup#all_history", as: :backup_history
8
+ get "backup/:id/edit", to: "backup#edit", as: :edit_backup
9
+ patch "backup/:id", to: "backup#update"
10
+ delete "backup/:id", to: "backup#destroy", as: :backup_destroy
11
+ post "backup/:id/trigger", to: "backup#trigger", as: :backup_trigger
12
+ get "backup/:id/history", to: "backup#history", as: :backup_config_history
13
+
14
+ root to: "backup#index"
15
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Safe example backup configuration.
4
+ #
5
+ # This seed intentionally contains no real hosts, usernames, paths, or
6
+ # passwords. Keep application-specific values in environment variables or
7
+ # Rails encrypted credentials, never in a committed seed file.
8
+ #
9
+ # Run with:
10
+ # rails runner db/seeds/backup_configs_safe.rb
11
+ #
12
+ # Or from the engine:
13
+ # backup_nexus:seed_backups
14
+
15
+ configs = [
16
+ {
17
+ name: "local_backup_example",
18
+ description: "Disabled local backup example; configure before enabling",
19
+ adapter: "mysql",
20
+ database_name: "app_development",
21
+ host: "localhost",
22
+ port: 3306,
23
+ username: "ENV[DATABASE_USERNAME]",
24
+ password: "ENV[DATABASE_PASSWORD]",
25
+ skip_tables: [],
26
+
27
+ storage_path: Rails.root.join("tmp", "backup_nexus_backups").to_s,
28
+ keep_count: 7,
29
+
30
+ compress: true,
31
+ bzip2_compress: false,
32
+ encrypted: false,
33
+ gpg_enabled: false,
34
+
35
+ rsync_enabled: false,
36
+ s3_enabled: false,
37
+ archive_enabled: false,
38
+
39
+ notify_on_success: false,
40
+ notify_on_failure: false,
41
+ email_notify: false,
42
+
43
+ schedule_cron: "",
44
+ enabled: false
45
+ }
46
+ ]
47
+
48
+ puts "Seeding #{configs.size} safe backup config..."
49
+
50
+ configs.each do |attrs|
51
+ config = BackupNexus::BackupConfig.find_or_initialize_by(name: attrs[:name])
52
+ config.assign_attributes(attrs)
53
+
54
+ if config.save
55
+ puts " ✓ #{config.name} (#{config.adapter}/#{config.database_name})"
56
+ else
57
+ puts " ✗ #{config.name}: #{config.errors.full_messages.join(', ')}"
58
+ end
59
+ end
60
+
61
+ puts "Done. #{BackupNexus::BackupConfig.count} configs total."
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BackupNexus
4
+ class BaseRecord < ActiveRecord::Base
5
+ self.abstract_class = true
6
+ end
7
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BackupNexus
4
+ class Configuration
5
+ attr_accessor :enabled
6
+ attr_accessor :database_url
7
+ attr_accessor :database_name
8
+ attr_accessor :database_yml
9
+ attr_accessor :table_prefix
10
+
11
+ def initialize
12
+ @enabled = false
13
+ @database_url = nil
14
+ @database_name = nil
15
+ @database_yml = nil
16
+ @table_prefix = "backup_nexus_"
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rake"
4
+
5
+ module BackupNexus
6
+ class Engine < ::Rails::Engine
7
+ isolate_namespace BackupNexus
8
+
9
+ engine_name "backup_nexus"
10
+
11
+ initializer "backup_nexus.database" do
12
+ ActiveSupport.on_load(:active_record) do
13
+ config = BackupNexus.configuration
14
+
15
+ if config.database_url.present?
16
+ uri = URI.parse(config.database_url)
17
+ BackupNexus::BaseRecord.establish_connection(
18
+ adapter: uri.scheme,
19
+ host: uri.host,
20
+ port: uri.port&.to_i,
21
+ username: URI.decode_www_form_component(uri.user || ""),
22
+ password: URI.decode_www_form_component(uri.password || ""),
23
+ database: uri.path&.gsub(%r{^/}, "")
24
+ )
25
+ elsif config.database_name.present?
26
+ yaml_path = Rails.root.join("config", "database.yml")
27
+ if yaml_path.exist?
28
+ yaml = YAML.safe_load(ERB.new(yaml_path.read).result, aliases: true) || {}
29
+ env_config = yaml[Rails.env.to_s] || yaml[Rails.env]
30
+ if env_config.is_a?(Hash)
31
+ db_config = env_config.symbolize_keys
32
+ db_config[:database] = config.database_name
33
+ BackupNexus::BaseRecord.establish_connection(**db_config)
34
+ end
35
+ end
36
+ elsif config.database_yml.present?
37
+ yaml_path = Rails.root.join(config.database_yml)
38
+ if yaml_path.exist?
39
+ yaml = YAML.safe_load(ERB.new(yaml_path.read).result, aliases: true) || {}
40
+ env_config = yaml[Rails.env.to_s] || yaml[Rails.env]
41
+ BackupNexus::BaseRecord.establish_connection(**env_config.symbolize_keys) if env_config.is_a?(Hash)
42
+ end
43
+ end
44
+ end
45
+ end
46
+
47
+ initializer "backup_nexus.rake_tasks" do
48
+ load "tasks/backup_nexus.rake" if Rake.respond_to?(:application)
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,3 @@
1
+ module BackupNexus
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails"
4
+ require "rails_nexus"
5
+ require "pagy"
6
+ require "uri"
7
+ require "yaml"
8
+ require "erb"
9
+ require "backup_nexus/version"
10
+ require "backup_nexus/configuration"
11
+ require "backup_nexus/base_record"
12
+ require "backup_nexus/engine"
13
+
14
+ module BackupNexus
15
+ class << self
16
+ attr_writer :configuration
17
+
18
+ def configuration
19
+ @configuration ||= Configuration.new
20
+ end
21
+
22
+ def configure
23
+ yield(configuration)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+ require "rails/generators/erb"
5
+
6
+ module BackupNexus
7
+ module Generators
8
+ class BackupGenerator < Rails::Generators::Base
9
+ desc "Set up backup_nexus backup directory structure and models"
10
+ source_root File.expand_path("templates/backup/backup", __dir__)
11
+
12
+ def create_backup_directories
13
+ empty_directory "config/backup"
14
+ empty_directory "config/backup/models"
15
+ empty_directory "config/backup/mysql-config"
16
+ empty_directory "storage/backup_nexus/backups"
17
+ empty_directory "storage/backup_nexus/backups/sync"
18
+ empty_directory "storage/backup_nexus/backups/logs"
19
+ end
20
+
21
+ def create_config_template
22
+ template "config.rb", "config/backup/config.rb"
23
+ end
24
+
25
+ def create_model_templates
26
+ template "models/daily_backup.rb", "config/backup/models/daily_backup.rb"
27
+ template "models/full_backup.rb", "config/backup/models/full_backup.rb"
28
+ template "models/sync_backup.rb", "config/backup/models/sync_backup.rb"
29
+ end
30
+
31
+ def create_schedule_template
32
+ template "schedule.rb", "config/backup/schedule.rb"
33
+ end
34
+
35
+ def create_helper_script
36
+ template "backup_helper.sh", "bin/backup_nexus-backup"
37
+ chmod "bin/backup_nexus-backup", 0o755
38
+ end
39
+
40
+ def create_mysql_config
41
+ template "mysql-config/db_config.cnf", "config/backup/mysql-config/db_config.cnf"
42
+ end
43
+
44
+ def add_to_gitignore
45
+ append_to_file ".gitignore", <<~GITIGNORE unless File.exist?(".gitignore") && File.read(".gitignore").include?("backup_nexus/backups")
46
+ \n# BackupNexus backups
47
+ storage/backup_nexus/backups/
48
+ config/backup/mysql-config/db_config.cnf
49
+ GITIGNORE
50
+ end
51
+
52
+ def show_readme
53
+ say ""
54
+ say "✅ Backup directory structure created!", :green
55
+ say ""
56
+ say "Next steps:"
57
+ say " 1. Edit config/backup/config.rb with your database credentials"
58
+ say " 2. Customize models in config/backup/models/"
59
+ say " 3. Install the schedule: whenever --write-crontab"
60
+ say " 4. Test: bin/backup_nexus-backup status"
61
+ say ""
62
+ say "Backup models created:"
63
+ say " - daily_backup: Incremental (skips large tables), local + remote"
64
+ say " - full_backup: All tables, local only"
65
+ say " - sync_backup: Remote sync to backup server"
66
+ say ""
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+
5
+ module BackupNexus
6
+ module Generators
7
+ class InstallGenerator < Rails::Generators::Base
8
+ source_root File.expand_path("templates", __dir__)
9
+
10
+ def create_migration
11
+ migration_template "migration.rb", "db/migrate/create_backup_nexus_tables.rb"
12
+ end
13
+
14
+ def mount_engine
15
+ route 'mount BackupNexus::Engine => "/backup_nexus", as: "backup_nexus"'
16
+ end
17
+
18
+ def create_backup_files
19
+ generate "backup_nexus:backup"
20
+ end
21
+
22
+ def show_readme
23
+ say "BackupNexus installed at /backup_nexus. Run bin/rails db:migrate next.", :green
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,152 @@
1
+ #!/bin/bash
2
+ # BackupNexus Backup Helper Script
3
+ # Generated by: rails generate backup_nexus:backup
4
+ #
5
+ # Usage:
6
+ # ./backup_helper.sh run <model> Run a backup model
7
+ # ./backup_helper.sh list List backup files
8
+ # ./backup_helper.sh status Show backup health status
9
+ # ./backup_helper.sh clean <days> Remove backups older than N days
10
+
11
+ set -e
12
+
13
+ # Configuration
14
+ BACKUP_DIR="${BACKUP_DUMP_PATH:-storage/backup_nexus/backups}"
15
+ BUNDLE_PATH="${BUNDLE_PATH:-.bundle}"
16
+ RUBY_ENV="${RUBY_ENV:-production}"
17
+
18
+ # Colors
19
+ RED='\033[0;31m'
20
+ GREEN='\033[0;32m'
21
+ YELLOW='\033[1;33m'
22
+ NC='\033[0m'
23
+
24
+ log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
25
+ log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
26
+ log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
27
+
28
+ # Run a backup
29
+ run_backup() {
30
+ local model="$1"
31
+ if [ -z "$model" ]; then
32
+ log_error "Usage: $0 run <model_name>"
33
+ exit 1
34
+ fi
35
+
36
+ # Lock to prevent concurrent runs
37
+ LOCKFILE="/tmp/backup_nexus_backup_${model}.lock"
38
+ exec 200>"$LOCKFILE"
39
+ if ! flock -n 200; then
40
+ log_warn "Backup '$model' is already running. Skipping."
41
+ exit 0
42
+ fi
43
+
44
+ log_info "Running backup: $model"
45
+ cd "$(dirname "$0")/../../.."
46
+
47
+ if bundle exec backup perform -t "$model" --triggered_by backup_nexus; then
48
+ log_info "Backup '$model' completed successfully."
49
+ else
50
+ log_error "Backup '$model' FAILED."
51
+ exit 1
52
+ fi
53
+ }
54
+
55
+ # List backup files
56
+ list_backups() {
57
+ local dir="$BACKUP_DIR"
58
+ if [ ! -d "$dir" ]; then
59
+ log_warn "No backup directory found at: $dir"
60
+ exit 0
61
+ fi
62
+
63
+ echo "Backup files in: $dir"
64
+ echo "─────────────────────────────────────────────"
65
+ printf "%-40s %10s %s\n" "FILE" "SIZE" "MODIFIED"
66
+ echo "─────────────────────────────────────────────"
67
+
68
+ find "$dir" -maxdepth 1 -type f -name "*.tar.gz*" -o -name "*.sql.gz*" | sort -r | head -20 | while read -r f; do
69
+ size=$(du -h "$f" | cut -f1)
70
+ modified=$(stat -c "%y" "$f" 2>/dev/null | cut -d'.' -f1 || date -r "$f" "+%Y-%m-%d %H:%M")
71
+ printf "%-40s %10s %s\n" "$(basename "$f")" "$size" "$modified"
72
+ done
73
+ }
74
+
75
+ # Show backup status
76
+ show_status() {
77
+ local dir="$BACKUP_DIR"
78
+ if [ ! -d "$dir" ]; then
79
+ echo "Status: NOT_CONFIGURED"
80
+ echo "No backup directory at: $dir"
81
+ exit 0
82
+ fi
83
+
84
+ local total_files
85
+ total_files=$(find "$dir" -maxdepth 1 -type f | wc -l)
86
+ local total_size
87
+ total_size=$(du -sh "$dir" 2>/dev/null | cut -f1 || echo "0B")
88
+
89
+ local latest_file
90
+ latest_file=$(find "$dir" -maxdepth 1 -type f -name "*.tar.gz*" -o -name "*.sql.gz*" 2>/dev/null | sort -r | head -1)
91
+
92
+ if [ -z "$latest_file" ]; then
93
+ echo "Status: WARNING - No backup files found"
94
+ else
95
+ local age_hours
96
+ age_hours=$(( ($(date +%s) - $(stat -c "%Y" "$latest_file" 2>/dev/null || stat -f "%m" "$latest_file")) / 3600 ))
97
+
98
+ if [ "$age_hours" -lt 24 ]; then
99
+ echo "Status: HEALTHY"
100
+ elif [ "$age_hours" -lt 72 ]; then
101
+ echo "Status: WARNING - Last backup ${age_hours}h ago"
102
+ else
103
+ echo "Status: CRITICAL - Last backup ${age_hours}h ago"
104
+ fi
105
+ fi
106
+
107
+ echo "Files: $total_files"
108
+ echo "Size: $total_size"
109
+ [ -n "$latest_file" ] && echo "Latest: $(basename "$latest_file")"
110
+ }
111
+
112
+ # Clean old backups
113
+ clean_backups() {
114
+ local days="${1:-30}"
115
+ local dir="$BACKUP_DIR"
116
+
117
+ if [ ! -d "$dir" ]; then
118
+ log_warn "No backup directory found at: $dir"
119
+ exit 0
120
+ fi
121
+
122
+ log_info "Removing backups older than $days days..."
123
+ find "$dir" -maxdepth 1 -type f -mtime +"$days" -delete
124
+ log_info "Cleanup complete."
125
+ }
126
+
127
+ # Main
128
+ case "${1:-help}" in
129
+ run)
130
+ run_backup "$2"
131
+ ;;
132
+ list)
133
+ list_backups
134
+ ;;
135
+ status)
136
+ show_status
137
+ ;;
138
+ clean)
139
+ clean_backups "$2"
140
+ ;;
141
+ *)
142
+ echo "BackupNexus Backup Helper"
143
+ echo ""
144
+ echo "Usage: $0 <command> [args]"
145
+ echo ""
146
+ echo "Commands:"
147
+ echo " run <model> Run a backup model (e.g., daily_backup)"
148
+ echo " list List recent backup files"
149
+ echo " status Show backup health status"
150
+ echo " clean [days] Remove backups older than N days (default: 30)"
151
+ ;;
152
+ esac
@@ -0,0 +1,27 @@
1
+ # encoding: utf-8
2
+
3
+ ##
4
+ # Backup v5.x Configuration
5
+ # Generated by backup_nexus
6
+ #
7
+ # Documentation: http://backup.github.io/backup
8
+ #
9
+
10
+ # Logging
11
+ # Logger.configure do
12
+ # console.quiet = true
13
+ # logfile.max_bytes = 2_000_000
14
+ # syslog.enabled = true
15
+ # syslog.ident = '<%= Rails.application.class.module_parent_name.underscore %>_backup'
16
+ # end
17
+
18
+ # Storage defaults
19
+ # Storage::Local.defaults do |local|
20
+ # local.path = 'storage/backup_nexus/backups'
21
+ # end
22
+
23
+ # Notifier defaults
24
+ # Notifier::Mail.defaults do |mail|
25
+ # mail.from = 'backup@<%= Rails.application.class.module_parent_name.underscore %>.com'
26
+ # mail.to = 'admin@<%= Rails.application.class.module_parent_name.underscore %>.com'
27
+ # end
@@ -0,0 +1,24 @@
1
+ # encoding: utf-8
2
+
3
+ # Daily Backup - Generated by backup_nexus
4
+ # Skips large/temporary tables for faster backups
5
+
6
+ Model.new(:daily_backup, '<%= Rails.application.class.module_parent_name %> Daily Backup') do
7
+
8
+ ## MySQL [Database]
9
+ database MySQL do |db|
10
+ db.name = "<%= Rails.configuration.database_configuration[Rails.env]['database'] %>"
11
+ db.port = <%= Rails.configuration.database_configuration[Rails.env]['port'] || 3306 %>
12
+ db.skip_tables = []
13
+ db.additional_options = ["--quick"]
14
+ end
15
+
16
+ ## Local [Storage]
17
+ store_with Local do |local|
18
+ local.path = 'storage/backup_nexus/backups'
19
+ local.keep = 30
20
+ end
21
+
22
+ ## Gzip [Compressor]
23
+ compress_with Gzip
24
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+ # Full backup template — all tables, local storage only
3
+
4
+ model :full_backup do
5
+ # Database
6
+ database Mysql do |db|
7
+ db.name = ENV["DATABASE_NAME"] || "myapp_production"
8
+ db.username = ENV["DATABASE_USER"] || "root"
9
+ db.password = ENV["DATABASE_PASSWORD"] || ""
10
+ db.host = ENV["DATABASE_HOST"] || "localhost"
11
+ db.port = (ENV["DATABASE_PORT"] || 3306).to_i
12
+ db.dump_options = {
13
+ single_transaction: true,
14
+ add_lock_tables: false
15
+ }
16
+ end
17
+
18
+ # Compress with Gzip
19
+ compress_with Gzip
20
+
21
+ # Store locally
22
+ store_with Local do |local|
23
+ local.path = ENV["BACKUP_DUMP_PATH"] || File.expand_path("storage/backup_nexus/backups", Rails.root)
24
+ local.keep = 10
25
+ end
26
+
27
+ # Notify on failure (optional)
28
+ notify_by Mail do |mail|
29
+ mail.on_success = false
30
+ mail.on_failure = true
31
+ mail.from = ENV["BACKUP_MAIL_FROM"] || "backup@example.com"
32
+ mail.to = ENV["BACKUP_MAIL_TO"] || "admin@example.com"
33
+ mail.smtp = { address: ENV["SMTP_HOST"] || "localhost", port: ENV["SMTP_PORT"] || 587 }
34
+ end
35
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+ # Sync backup template — remote sync to backup server
3
+
4
+ model :sync_backup do
5
+ # Database
6
+ database Mysql do |db|
7
+ db.name = ENV["DATABASE_NAME"] || "myapp_production"
8
+ db.username = ENV["DATABASE_USER"] || "root"
9
+ db.password = ENV["DATABASE_PASSWORD"] || ""
10
+ db.host = ENV["DATABASE_HOST"] || "localhost"
11
+ db.port = (ENV["DATABASE_PORT"] || 3306).to_i
12
+
13
+ # Skip large/temporary tables
14
+ skip_tables = ENV["BACKUP_SKIP_TABLES"] || "sessions,caches,active_storage"
15
+ skip_tables.split(",").each { |t| db.skip_tables << t.strip }
16
+ end
17
+
18
+ # Compress with Gzip
19
+ compress_with Gzip
20
+
21
+ # Store locally (staging area)
22
+ store_with Local do |local|
23
+ local.path = ENV["BACKUP_DUMP_PATH"] || File.expand_path("storage/backup_nexus/backups/sync", Rails.root)
24
+ local.keep = 1
25
+ end
26
+
27
+ # Sync to remote server
28
+ notify_by Sync do |sync|
29
+ sync.directories do |directory|
30
+ directory.path = ENV["BACKUP_DUMP_PATH"] || File.expand_path("storage/backup_nexus/backups/sync", Rails.root)
31
+ end
32
+
33
+ connection do |conn|
34
+ conn.host = ENV["BACKUP_RSYNC_HOST"] || "backup.example.com"
35
+ conn.port = ENV["BACKUP_RSYNC_PORT"] || 22
36
+ conn.username = ENV["BACKUP_RSYNC_USER"] || "backup"
37
+ conn.ssh_options = {
38
+ keys: ENV["BACKUP_SSH_KEY"] || File.expand_path("~/.ssh/id_rsa"),
39
+ timeout: 30
40
+ }
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,15 @@
1
+ # BackupNexus Backup MySQL Configuration
2
+ # Generated by: rails generate backup_nexus:backup
3
+ #
4
+ # This file is used by the backup gem for database authentication.
5
+ # Keep this file secure and do not commit to version control.
6
+
7
+ [client]
8
+ user=<%= ENV['DATABASE_USER'] || 'root' %>
9
+ password=<%= ENV['DATABASE_PASSWORD'] || '' %>
10
+ host=<%= ENV['DATABASE_HOST'] || 'localhost' %>
11
+ port=<%= (ENV['DATABASE_PORT'] || 3306).to_i %>
12
+ database=<%= ENV['DATABASE_NAME'] || 'myapp_production' %>
13
+
14
+ # Dump options
15
+ default-character-set=utf8mb4
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+ # BackupNexus Backup Schedule
3
+ # Generated by: rails generate backup_nexus:backup
4
+ #
5
+ # This file is parsed by the BackupService to show schedule info in the UI.
6
+ # Actual cron should be installed separately: whenever --write-crontab
7
+
8
+ # ─── Backup Schedule ──────────────────────────────────────────────
9
+
10
+ # Full backup daily at 2:00 AM (all tables, local only)
11
+ every 1.day, at: "2:00 am" do
12
+ command "cd #{File.expand_path('../..', __FILE__)} && bundle exec backup perform -t full_backup --triggered_by system"
13
+ end
14
+
15
+ # Incremental backup every 4 hours (skipping large tables)
16
+ every 4.hours do
17
+ command "cd #{File.expand_path('../..', __FILE__)} && bundle exec backup perform -t incremental_backup --triggered_by system"
18
+ end
19
+
20
+ # Remote sync weekly on Sunday at 3:00 AM
21
+ every 1.week, at: "3:00 am" do
22
+ command "cd #{File.expand_path('../..', __FILE__)} && bundle exec backup perform -t sync_backup --triggered_by system"
23
+ end
24
+
25
+ # Cleanup old backups monthly
26
+ every 1.month, at: "4:00 am" do
27
+ command "cd #{File.expand_path('../..', __FILE__)} && bundle exec backup perform -t full_backup --cleanup"
28
+ end