rails_nexus 2.0.0 → 2.0.1

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.
@@ -15,197 +15,121 @@
15
15
  </svg>
16
16
  <h1 class="text-2xl font-bold" style="color: var(--rn-text)">Backup Management</h1>
17
17
  </div>
18
- <div class="flex gap-2">
19
- <a href="<%= backup_settings_path %>" class="rn-btn rn-btn-ghost">Settings</a>
20
- <a href="<%= backup_files_path %>" class="rn-btn rn-btn-ghost">View All Files</a>
21
- </div>
22
18
  </div>
23
19
 
24
20
  <%# ─── Health Status ───────────────────────────────────────── %>
25
- <% if @health[:status] == "not_configured" %>
26
- <div class="rn-card" style="border-left: 3px solid var(--rn-text-muted)">
27
- <div class="p-4 flex items-center gap-3">
28
- <span class="w-3 h-3 rounded-full" style="background: var(--rn-text-muted)"></span>
29
- <div>
30
- <span class="text-sm font-semibold" style="color: var(--rn-text)">Backup not configured</span>
31
- <p class="text-xs mt-1" style="color: var(--rn-text-muted)">Set <code>config.backup_enabled = true</code> and configure paths in your initializer.</p>
32
- </div>
33
- </div>
34
- </div>
35
- <% else %>
36
- <div class="rn-card" style="border-left: 3px solid <%= @health[:status] == 'healthy' ? 'var(--rn-success)' : @health[:status] == 'warning' ? 'var(--rn-warning)' : 'var(--rn-danger)' %>">
37
- <div class="p-4 flex items-center gap-3">
38
- <span class="w-3 h-3 rounded-full" style="background: <%= @health[:status] == 'healthy' ? 'var(--rn-success)' : @health[:status] == 'warning' ? 'var(--rn-warning)' : 'var(--rn-danger)' %>"></span>
39
- <div>
40
- <span class="text-sm font-semibold" style="color: var(--rn-text)"><%= @health[:message] %></span>
41
- </div>
21
+ <div class="rn-card" style="border-left: 3px solid <%= @health[:status] == 'healthy' ? 'var(--rn-success)' : @health[:status] == 'warning' ? 'var(--rn-warning)' : 'var(--rn-danger)' %>">
22
+ <div class="p-4 flex items-center gap-3">
23
+ <span class="w-3 h-3 rounded-full" style="background: <%= @health[:status] == 'healthy' ? 'var(--rn-success)' : @health[:status] == 'warning' ? 'var(--rn-warning)' : 'var(--rn-danger)' %>"></span>
24
+ <div>
25
+ <span class="text-sm font-semibold" style="color: var(--rn-text)"><%= @health[:message] %></span>
42
26
  </div>
43
27
  </div>
44
- <% end %>
28
+ </div>
45
29
 
46
30
  <%# ─── Summary Stats ───────────────────────────────────────── %>
47
- <% if @summary %>
48
- <div class="rn-stats">
49
- <div class="rn-stat">
50
- <span class="rn-stat-label">Total Backups</span>
51
- <span class="rn-stat-value"><%= @summary[:total_files] %></span>
52
- <span class="rn-stat-change"><%= @summary[:total_size_human] %></span>
53
- </div>
54
- <div class="rn-stat">
55
- <span class="rn-stat-label">Last Backup</span>
56
- <span class="rn-stat-value"><%= @summary[:last_backup] ? time_ago_in_words(@summary[:last_backup]) + " ago" : "Never" %></span>
57
- <span class="rn-stat-change"><%= @summary[:last_backup_age_hours] ? "#{@summary[:last_backup_age_hours]}h ago" : "" %></span>
58
- </div>
59
- <div class="rn-stat">
60
- <span class="rn-stat-label">Backup Models</span>
61
- <span class="rn-stat-value"><%= @summary[:models_count] %></span>
62
- <span class="rn-stat-change">Configured</span>
63
- </div>
64
- <div class="rn-stat">
65
- <span class="rn-stat-label">Health</span>
66
- <span class="rn-stat-value" style="color: <%= @summary[:healthy] ? 'var(--rn-success)' : 'var(--rn-danger)' %>">
67
- <%= @summary[:healthy] ? "✓ Healthy" : "⚠ Issues" %>
68
- </span>
69
- <span class="rn-stat-change"><%= @summary[:alerts]&.size || 0 %> alerts</span>
70
- </div>
31
+ <div class="rn-stats">
32
+ <div class="rn-stat">
33
+ <span class="rn-stat-label">Total Backups</span>
34
+ <span class="rn-stat-value"><%= @summary[:total] %></span>
35
+ <span class="rn-stat-change"><%= @summary[:total_size_human] %> total</span>
36
+ </div>
37
+ <div class="rn-stat">
38
+ <span class="rn-stat-label">Successful</span>
39
+ <span class="rn-stat-value" style="color: var(--rn-success)"><%= @summary[:successful] %></span>
40
+ <span class="rn-stat-change">All time</span>
71
41
  </div>
72
- <% end %>
42
+ <div class="rn-stat">
43
+ <span class="rn-stat-label">Failed</span>
44
+ <span class="rn-stat-value" style="color: var(--rn-danger)"><%= @summary[:failed] %></span>
45
+ <span class="rn-stat-change">All time</span>
46
+ </div>
47
+ <div class="rn-stat">
48
+ <span class="rn-stat-label">Last 7 Days</span>
49
+ <span class="rn-stat-value"><%= @summary[:recent_count] %></span>
50
+ <span class="rn-stat-change"><%= @summary[:recent_success] %> ok, <%= @summary[:recent_failed] %> failed</span>
51
+ </div>
52
+ </div>
73
53
 
74
- <%# ─── Alerts ──────────────────────────────────────────────── %>
75
- <% if @summary && @summary[:alerts]&.any? %>
76
- <% @summary[:alerts].each do |alert| %>
77
- <div class="rn-card" style="border-left: 3px solid <%= alert[:level] == 'critical' ? 'var(--rn-danger)' : alert[:level] == 'warning' ? 'var(--rn-warning)' : 'var(--rn-info)' %>">
78
- <div class="p-3 flex items-center gap-2">
79
- <span class="text-sm" style="color: var(--rn-text)"><%= alert[:message] %></span>
80
- </div>
81
- </div>
82
- <% end %>
83
- <% end %>
54
+ <%# ─── Trigger Backup ──────────────────────────────────────── %>
55
+ <div class="rn-card">
56
+ <div class="p-4" style="border-bottom: 1px solid var(--rn-border-light)">
57
+ <h2 class="text-sm font-semibold" style="color: var(--rn-text)">Run Backup</h2>
58
+ <p class="text-xs mt-1" style="color: var(--rn-text-muted)">Trigger a database dump. The record will be saved to the table.</p>
59
+ </div>
60
+ <div class="p-4 flex gap-3">
61
+ <% %w[primary full sync].each do |model| %>
62
+ <%= button_to model.titleize, backup_trigger_path(model: model),
63
+ method: :post,
64
+ class: "rn-btn rn-btn-primary rn-btn-sm",
65
+ data: { turbo_confirm: "Run #{model} backup now?" } %>
66
+ <% end %>
67
+ </div>
68
+ </div>
84
69
 
85
- <%# ─── Backup Models ───────────────────────────────────────── %>
86
- <% if @models.any? %>
87
- <div class="rn-card">
88
- <div class="p-4" style="border-bottom: 1px solid var(--rn-border-light)">
89
- <div class="flex items-center gap-2">
90
- <svg class="w-4 h-4" style="color: var(--rn-primary)" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
91
- <path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 00-3.375-3.375h-1.5A1.125 1.125 0 0113.5 7.125v-1.5a3.375 3.375 0 00-3.375-3.375H8.25m0 12.75h7.5m-7.5 3H12M10.5 2.25H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 00-9-9z" />
92
- </svg>
93
- <h2 class="text-sm font-semibold" style="color: var(--rn-text)">Backup Models</h2>
94
- </div>
70
+ <%# ─── Recent Backups Table ────────────────────────────────── %>
71
+ <div class="rn-card">
72
+ <div class="p-4" style="border-bottom: 1px solid var(--rn-border-light)">
73
+ <div class="flex items-center gap-2">
74
+ <svg class="w-4 h-4" style="color: var(--rn-primary)" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
75
+ <path stroke-linecap="round" stroke-linejoin="round" d="M12 6v6h4.5m4.5 0a9 9 0 11-18 0 9 9 0 0118 0z" />
76
+ </svg>
77
+ <h2 class="text-sm font-semibold" style="color: var(--rn-text)">Backup History</h2>
95
78
  </div>
79
+ <p class="text-xs mt-1" style="color: var(--rn-text-muted)">All backup runs recorded in the database</p>
80
+ </div>
81
+
82
+ <% if @records.any? %>
96
83
  <div class="rn-table-wrap">
97
84
  <table class="rn-table">
98
85
  <thead>
99
86
  <tr>
100
87
  <th>Model</th>
101
- <th>Database</th>
102
- <th>Storage</th>
103
- <th>Encryption</th>
104
- <th>Keep</th>
105
- <th style="text-align: right">Actions</th>
88
+ <th>Status</th>
89
+ <th>Size</th>
90
+ <th>Duration</th>
91
+ <th>Triggered By</th>
92
+ <th>Time</th>
93
+ <th></th>
106
94
  </tr>
107
95
  </thead>
108
96
  <tbody>
109
- <% @models.each do |model| %>
97
+ <% @records.each do |record| %>
110
98
  <tr>
111
99
  <td>
112
- <span class="font-medium" style="color: var(--rn-text)"><%= model[:name] %></span>
113
- <br><span class="text-xs" style="color: var(--rn-text-muted)"><%= model[:description] %></span>
100
+ <span class="font-medium" style="color: var(--rn-text)"><%= record.model_name %></span>
114
101
  </td>
115
- <td><span class="rn-badge <%= model[:has_mysql] ? 'rn-badge-success' : 'rn-badge-muted' %>">MySQL</span></td>
116
102
  <td>
117
- <span class="rn-badge <%= model[:has_local] ? 'rn-badge-info' : '' %>">Local</span>
118
- <% if model[:has_rsync] %><span class="rn-badge rn-badge-warning">RSync</span><% end %>
103
+ <span class="rn-badge rn-badge-<%= record.status == 'success' ? 'success' : record.status == 'failed' ? 'danger' : 'warning' %>">
104
+ <%= record.status.capitalize %>
105
+ </span>
119
106
  </td>
120
- <td><span class="rn-badge <%= model[:has_encryption] ? 'rn-badge-success' : 'rn-badge-muted' %>"><%= model[:has_encryption] ? 'Encrypted' : 'None' %></span></td>
121
- <td><%= model[:keep_count] || '∞' %></td>
122
- <td style="text-align: right">
123
- <%= button_to "Trigger", backup_trigger_path(model: model[:name]),
124
- method: :post,
125
- class: "rn-btn rn-btn-primary rn-btn-xs",
126
- data: { turbo_confirm: "Run #{model[:name]} backup now?" } %>
107
+ <td>
108
+ <span class="text-xs" style="color: var(--rn-text-secondary)"><%= record.file_size ? number_to_human_size(record.file_size) : "—" %></span>
127
109
  </td>
128
- </tr>
129
- <% end %>
130
- </tbody>
131
- </table>
132
- </div>
133
- </div>
134
- <% end %>
135
-
136
- <%# ─── Recent Backups ──────────────────────────────────────── %>
137
- <% if @backup_service.backup_files.any? %>
138
- <div class="rn-card">
139
- <div class="p-4" style="border-bottom: 1px solid var(--rn-border-light)">
140
- <div class="flex items-center gap-2">
141
- <svg class="w-4 h-4" style="color: var(--rn-primary)" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
142
- <path stroke-linecap="round" stroke-linejoin="round" d="M12 6v6h4.5m4.5 0a9 9 0 11-18 0 9 9 0 0118 0z" />
143
- </svg>
144
- <h2 class="text-sm font-semibold" style="color: var(--rn-text)">Recent Backups</h2>
145
- </div>
146
- </div>
147
- <div class="rn-table-wrap">
148
- <table class="rn-table">
149
- <thead>
150
- <tr>
151
- <th>File</th>
152
- <th>Size</th>
153
- <th>Created</th>
154
- <th>Status</th>
155
- </tr>
156
- </thead>
157
- <tbody>
158
- <% @backup_service.backup_files.first(10).each do |file| %>
159
- <tr>
160
110
  <td>
161
- <span class="rn-mono text-xs" style="color: var(--rn-text)"><%= file[:name] %></span>
111
+ <span class="text-xs" style="color: var(--rn-text-secondary)"><%= record.duration ? "#{record.duration.round(1)}s" : "—" %></span>
162
112
  </td>
163
- <td><span class="text-xs" style="color: var(--rn-text-secondary)"><%= file[:size_human] %></span></td>
164
- <td><span class="text-xs" style="color: var(--rn-text-muted)"><%= time_ago_in_words(file[:created_at]) %> ago</span></td>
165
113
  <td>
166
- <span class="rn-badge <%= file[:age_hours] < 24 ? 'rn-badge-success' : file[:age_hours] < 72 ? 'rn-badge-warning' : 'rn-badge-muted' %>">
167
- <%= file[:age_hours] < 24 ? 'Recent' : file[:age_hours] < 72 ? 'Aging' : 'Old' %>
168
- </span>
114
+ <span class="text-xs" style="color: var(--rn-text-muted)"><%= record.triggered_by || "—" %></span>
115
+ </td>
116
+ <td>
117
+ <span class="text-xs" style="color: var(--rn-text-muted)"><%= record.started_at ? time_ago_in_words(record.started_at) + " ago" : "—" %></span>
118
+ </td>
119
+ <td>
120
+ <% if record.error_message.present? %>
121
+ <span class="text-xs" style="color: var(--rn-danger)" title="<%= record.error_message %>">⚠</span>
122
+ <% end %>
169
123
  </td>
170
124
  </tr>
171
125
  <% end %>
172
126
  </tbody>
173
127
  </table>
174
128
  </div>
175
- </div>
176
- <% end %>
177
-
178
- <%# ─── Cron Schedule ───────────────────────────────────────── %>
179
- <% if @schedule && @schedule[:entries].any? %>
180
- <div class="rn-card">
181
- <div class="p-4" style="border-bottom: 1px solid var(--rn-border-light)">
182
- <div class="flex items-center gap-2">
183
- <svg class="w-4 h-4" style="color: var(--rn-primary)" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
184
- <path stroke-linecap="round" stroke-linejoin="round" d="M6.75 3v2.25M17.25 3v2.25M3 18.75V7.5a2.25 2.25 0 012.25-2.25h13.5A2.25 2.25 0 0121 7.5v11.25m-18 0A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75m-18 0v-7.5A2.25 2.25 0 015.25 9h13.5A2.25 2.25 0 0121 11.25v7.5" />
185
- </svg>
186
- <h2 class="text-sm font-semibold" style="color: var(--rn-text)">Schedule</h2>
187
- </div>
129
+ <% else %>
130
+ <div class="p-8 text-center">
131
+ <p class="text-sm" style="color: var(--rn-text-muted)">No backups recorded yet. Run a backup above to get started.</p>
188
132
  </div>
189
- <div class="rn-table-wrap">
190
- <table class="rn-table">
191
- <thead>
192
- <tr>
193
- <th>Frequency</th>
194
- <th>Time</th>
195
- <th>Command</th>
196
- </tr>
197
- </thead>
198
- <tbody>
199
- <% @schedule[:entries].each do |entry| %>
200
- <tr>
201
- <td><span class="text-sm" style="color: var(--rn-text)"><%= entry[:frequency] %></span></td>
202
- <td><span class="text-sm" style="color: var(--rn-text-secondary)"><%= entry[:time] || "All day" %></span></td>
203
- <td><span class="rn-mono text-xs" style="color: var(--rn-text-muted)"><%= entry[:command] %></span></td>
204
- </tr>
205
- <% end %>
206
- </tbody>
207
- </table>
208
- </div>
209
- </div>
210
- <% end %>
133
+ <% end %>
134
+ </div>
211
135
  </div>
data/config/routes.rb CHANGED
@@ -45,9 +45,8 @@ RailsNexus::Engine.routes.draw do
45
45
  get "backup", to: "backup#index", as: :backup
46
46
  get "backup/files", to: "backup#files", as: :backup_files
47
47
  post "backup/trigger/:model", to: "backup#trigger", as: :backup_trigger
48
+ delete "backup/:id", to: "backup#destroy", as: :backup_destroy
48
49
  get "backup/health", to: "backup#health", as: :backup_health
49
- get "backup/settings", to: "backup#settings", as: :backup_settings
50
- patch "backup/settings", to: "backup#update_settings", as: :backup_update_settings
51
50
 
52
51
  # Settings and webhook management
53
52
  get "settings", to: "settings#index", as: :settings
@@ -8,16 +8,6 @@ module RailsNexus
8
8
  class InstallGenerator < Rails::Generators::Base
9
9
  include Rails::Generators::Migration
10
10
 
11
- MIGRATIONS = {
12
- "migration.rb" => "create_rails_nexus_exceptions.rb",
13
- "migration_advanced_features.rb" => "add_advanced_features_to_rails_nexus_exceptions.rb",
14
- "migration_platform_detection.rb" => "add_platform_to_rails_nexus_exceptions.rb",
15
- "migration_workflow.rb" => "add_workflow_to_rails_nexus.rb",
16
- "migration_cron_jobs.rb" => "create_rails_nexus_cron_jobs.rb",
17
- "migration_webhook_deliveries.rb" => "create_rails_nexus_webhook_deliveries.rb",
18
- "migration_new_schema.rb" => "create_rails_nexus_metrics_tables.rb"
19
- }.freeze
20
-
21
11
  source_root File.expand_path("templates", __dir__)
22
12
  desc "Install RailsNexus into your Rails application"
23
13
 
@@ -26,9 +16,7 @@ module RailsNexus
26
16
  end
27
17
 
28
18
  def create_migration_files
29
- MIGRATIONS.each do |source, destination|
30
- migration_template source, "db/migrate/#{destination}"
31
- end
19
+ migration_template "migration.rb", "db/migrate/create_rails_nexus_tables.rb"
32
20
  end
33
21
 
34
22
  def create_initializer
@@ -1,18 +1,50 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class CreateRailsNexusLoggedExceptions < ActiveRecord::Migration<%= "[#{ActiveRecord::Migration.current_version}]" %>
3
+ class CreateRailsNexusTables < ActiveRecord::Migration[<%= "[#{ActiveRecord::Migration.current_version}]" %>]
4
4
  def change
5
+ # ─── rails_nexus_exceptions ──────────────────────────────────────
5
6
  create_table :rails_nexus_exceptions do |t|
6
- t.string :exception_class
7
- t.string :controller_name
8
- t.string :action_name
9
- t.text :message
10
- t.text :backtrace
11
- t.text :environment
12
- t.text :request
13
- t.string :user_info
14
- t.string :user_agent
15
- t.string :remote_ip
7
+ # Core exception data
8
+ t.string :exception_class
9
+ t.string :controller_name
10
+ t.string :action_name
11
+ t.text :message
12
+ t.text :backtrace
13
+ t.text :environment
14
+ t.text :request
15
+ t.string :user_info
16
+ t.string :user_agent
17
+ t.string :remote_ip
18
+
19
+ # Fingerprinting & deduplication
20
+ t.string :fingerprint
21
+ t.integer :occurrence_count, default: 1
22
+
23
+ # Platform detection
24
+ t.string :platform, default: "web"
25
+ t.string :platform_version
26
+ t.string :device_type
27
+ t.string :app_version
28
+
29
+ # Advanced features
30
+ t.text :cause_chain
31
+ t.text :breadcrumbs
32
+ t.text :system_health
33
+ t.text :local_variables
34
+ t.text :instance_variables
35
+
36
+ # User impact tracking
37
+ t.string :user_id
38
+ t.string :user_type
39
+
40
+ # Workflow management
41
+ t.string :priority
42
+ t.string :assigned_to
43
+ t.datetime :assigned_at
44
+ t.datetime :snoozed_until
45
+ t.boolean :muted, default: false
46
+ t.datetime :muted_at
47
+ t.integer :comments_count, default: 0
16
48
 
17
49
  t.timestamps
18
50
  end
@@ -20,5 +52,81 @@ class CreateRailsNexusLoggedExceptions < ActiveRecord::Migration<%= "[#{ActiveRe
20
52
  add_index :rails_nexus_exceptions, :created_at
21
53
  add_index :rails_nexus_exceptions, :exception_class
22
54
  add_index :rails_nexus_exceptions, [:controller_name, :action_name]
55
+ add_index :rails_nexus_exceptions, :fingerprint
56
+ add_index :rails_nexus_exceptions, :occurrence_count
57
+ add_index :rails_nexus_exceptions, :platform
58
+ add_index :rails_nexus_exceptions, [:platform, :exception_class]
59
+ add_index :rails_nexus_exceptions, :priority
60
+ add_index :rails_nexus_exceptions, :assigned_to
61
+ add_index :rails_nexus_exceptions, :muted
62
+ add_index :rails_nexus_exceptions, :user_id
63
+
64
+ # ─── rails_nexus_comments ────────────────────────────────────────
65
+ create_table :rails_nexus_comments do |t|
66
+ t.references :logged_exception, null: false, foreign_key: { to_table: :rails_nexus_exceptions }
67
+ t.string :author, null: false
68
+ t.text :body, null: false
69
+ t.string :comment_type, default: "comment"
70
+
71
+ t.timestamps
72
+ end
73
+
74
+ add_index :rails_nexus_comments, [:logged_exception_id, :created_at]
75
+
76
+ # ─── rails_nexus_cron_jobs ───────────────────────────────────────
77
+ create_table :rails_nexus_cron_jobs do |t|
78
+ t.string :name, null: false
79
+ t.string :status, null: false, default: "pending"
80
+ t.text :output
81
+ t.text :error_message
82
+ t.float :duration
83
+ t.string :hostname
84
+ t.json :metadata
85
+ t.datetime :started_at
86
+ t.datetime :finished_at
87
+
88
+ t.timestamps
89
+ end
90
+
91
+ add_index :rails_nexus_cron_jobs, :name
92
+ add_index :rails_nexus_cron_jobs, :status
93
+ add_index :rails_nexus_cron_jobs, :created_at
94
+ add_index :rails_nexus_cron_jobs, :started_at
95
+
96
+ # ─── rails_nexus_webhook_deliveries ──────────────────────────────
97
+ create_table :rails_nexus_webhook_deliveries do |t|
98
+ t.string :url, null: false
99
+ t.string :status, null: false, default: "pending"
100
+ t.integer :response_code
101
+ t.text :request_body
102
+ t.text :response_body
103
+ t.float :duration
104
+ t.text :error_message
105
+ t.string :event_type
106
+ t.json :metadata
107
+
108
+ t.timestamps
109
+ end
110
+
111
+ add_index :rails_nexus_webhook_deliveries, :status
112
+ add_index :rails_nexus_webhook_deliveries, :created_at
113
+ add_index :rails_nexus_webhook_deliveries, :url
114
+
115
+ # ─── rails_nexus_backups ─────────────────────────────────────────
116
+ create_table :rails_nexus_backups do |t|
117
+ t.string :model_name, null: false
118
+ t.string :status, null: false
119
+ t.text :file_path
120
+ t.bigint :file_size
121
+ t.float :duration
122
+ t.text :error_message
123
+ t.string :triggered_by
124
+ t.datetime :started_at, null: false
125
+ t.datetime :completed_at
126
+ end
127
+
128
+ add_index :rails_nexus_backups, [:model_name, :started_at]
129
+ add_index :rails_nexus_backups, :status
130
+ add_index :rails_nexus_backups, :started_at
23
131
  end
24
132
  end
@@ -1,3 +1,3 @@
1
1
  module RailsNexus
2
- VERSION = "2.0.0"
2
+ VERSION = "2.0.1"
3
3
  end
@@ -227,4 +227,12 @@ namespace :rails_nexus do
227
227
  count = RailsNexus::WebhookDelivery.where("created_at < ?", days.days.ago).delete_all
228
228
  puts "✓ Deleted #{count} webhook delivery records older than #{days} days"
229
229
  end
230
+
231
+ desc "Clean up old backup records and files (default: 30 days)"
232
+ task :backup_cleanup, [:days] => :environment do |_t, args|
233
+ days = (args[:days] || 30).to_i
234
+ service = RailsNexus::BackupService.new
235
+ result = service.cleanup!(retention_days: days)
236
+ puts "✓ Deleted #{result[:deleted]} backup records older than #{days} days"
237
+ end
230
238
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_nexus
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tamiru Hailu
@@ -142,20 +142,14 @@ files:
142
142
  - app/models/rails_nexus/base_record.rb
143
143
  - app/models/rails_nexus/comment.rb
144
144
  - app/models/rails_nexus/cron_job.rb
145
- - app/models/rails_nexus/database_stat.rb
146
- - app/models/rails_nexus/event.rb
147
145
  - app/models/rails_nexus/logged_exception.rb
148
146
  - app/models/rails_nexus/logged_exception_n1.rb
149
- - app/models/rails_nexus/metric.rb
150
- - app/models/rails_nexus/nginx_metric.rb
151
- - app/models/rails_nexus/server_metric.rb
152
147
  - app/models/rails_nexus/webhook_delivery.rb
153
148
  - app/services/rails_nexus/backup_service.rb
154
149
  - app/views/layouts/rails_nexus/application.html.erb
155
150
  - app/views/rails_nexus/analytics/index.html.erb
156
151
  - app/views/rails_nexus/backup/files.html.erb
157
152
  - app/views/rails_nexus/backup/index.html.erb
158
- - app/views/rails_nexus/backup/settings.html.erb
159
153
  - app/views/rails_nexus/cron_jobs/index.html.erb
160
154
  - app/views/rails_nexus/database_health/index.html.erb
161
155
  - app/views/rails_nexus/logged_exceptions/_comments_list.html.erb
@@ -181,7 +175,6 @@ files:
181
175
  - config/initializers/rails_nexus.rb
182
176
  - config/locales/en.yml
183
177
  - config/routes.rb
184
- - db/migrate/20240330122311_create_rails_nexus_logged_exceptions.rb
185
178
  - lib/generators/rails_nexus/backup_generator.rb
186
179
  - lib/generators/rails_nexus/customize_generator.rb
187
180
  - lib/generators/rails_nexus/install_generator.rb
@@ -198,12 +191,6 @@ files:
198
191
  - lib/generators/rails_nexus/templates/javascript/controllers/rails_nexus_sidebar_controller.js
199
192
  - lib/generators/rails_nexus/templates/javascript/controllers/rails_nexus_theme_controller.js
200
193
  - lib/generators/rails_nexus/templates/migration.rb
201
- - lib/generators/rails_nexus/templates/migration_advanced_features.rb
202
- - lib/generators/rails_nexus/templates/migration_cron_jobs.rb
203
- - lib/generators/rails_nexus/templates/migration_new_schema.rb
204
- - lib/generators/rails_nexus/templates/migration_platform_detection.rb
205
- - lib/generators/rails_nexus/templates/migration_webhook_deliveries.rb
206
- - lib/generators/rails_nexus/templates/migration_workflow.rb
207
194
  - lib/generators/rails_nexus/templates/rails_nexus.rb
208
195
  - lib/generators/rails_nexus/templates/views/layouts/rails_nexus/application.html.erb
209
196
  - lib/generators/rails_nexus/templates/views/rails_nexus/logged_exceptions/_exceptions.html.erb