rails_nexus 2.1.0 → 2.1.3

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 (62) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +110 -0
  3. data/README.md +68 -13
  4. data/SECURITY.md +11 -0
  5. data/THIRD_PARTY_NOTICES.md +14 -0
  6. data/app/assets/config/rails_nexus_manifest.js +1 -1
  7. data/app/assets/javascripts/rails_nexus/application.js +55 -0
  8. data/app/controllers/rails_nexus/analytics_controller.rb +13 -26
  9. data/app/controllers/rails_nexus/application_controller.rb +6 -2
  10. data/app/controllers/rails_nexus/cron_jobs_controller.rb +1 -9
  11. data/app/controllers/rails_nexus/database_health_controller.rb +0 -10
  12. data/app/controllers/rails_nexus/logged_exceptions_controller.rb +0 -2
  13. data/app/controllers/rails_nexus/n1_patterns_controller.rb +0 -2
  14. data/app/controllers/rails_nexus/settings_controller.rb +1 -39
  15. data/app/controllers/rails_nexus/source_code_controller.rb +9 -13
  16. data/app/controllers/rails_nexus/stats_controller.rb +33 -159
  17. data/app/helpers/rails_nexus/logged_exceptions_helper.rb +4 -49
  18. data/app/helpers/rails_nexus/source_code_helper.rb +49 -10
  19. data/app/javascript/rails_nexus/application.js +15 -3
  20. data/app/models/rails_nexus/logged_exception.rb +27 -13
  21. data/app/views/layouts/rails_nexus/_sidebar_navigation.html.erb +0 -11
  22. data/app/views/layouts/rails_nexus/application.html.erb +2 -13
  23. data/app/views/rails_nexus/stats/index.html.erb +1 -102
  24. data/config/routes.rb +0 -11
  25. data/lib/generators/rails_nexus/install_generator.rb +1 -1
  26. data/lib/generators/rails_nexus/templates/INSTALL.md +1 -0
  27. data/lib/generators/rails_nexus/templates/migration.rb +0 -82
  28. data/lib/generators/rails_nexus/templates/rails_nexus.rb +3 -0
  29. data/lib/generators/rails_nexus/templates/views/layouts/rails_nexus/application.html.erb +1 -1
  30. data/lib/rails_nexus/configuration.rb +10 -45
  31. data/lib/rails_nexus/database_adapter.rb +53 -0
  32. data/lib/rails_nexus/engine.rb +6 -17
  33. data/lib/rails_nexus/logger.rb +1 -12
  34. data/lib/rails_nexus/notifications.rb +27 -20
  35. data/lib/rails_nexus/version.rb +1 -1
  36. data/lib/rails_nexus/webhook_client.rb +151 -0
  37. data/lib/rails_nexus.rb +37 -23
  38. data/lib/tasks/rails_nexus.rake +0 -80
  39. data/rails_nexus.gemspec +4 -5
  40. metadata +12 -41
  41. data/app/controllers/rails_nexus/backup_controller.rb +0 -120
  42. data/app/jobs/rails_nexus/backup_job.rb +0 -18
  43. data/app/models/rails_nexus/backup.rb +0 -107
  44. data/app/models/rails_nexus/backup_config.rb +0 -158
  45. data/app/services/rails_nexus/backup_runner.rb +0 -62
  46. data/app/services/rails_nexus/backup_service.rb +0 -682
  47. data/app/views/rails_nexus/backup/_form.html.erb +0 -334
  48. data/app/views/rails_nexus/backup/config_history.html.erb +0 -67
  49. data/app/views/rails_nexus/backup/edit.html.erb +0 -15
  50. data/app/views/rails_nexus/backup/history.html.erb +0 -75
  51. data/app/views/rails_nexus/backup/index.html.erb +0 -112
  52. data/app/views/rails_nexus/backup/new.html.erb +0 -15
  53. data/config/importmap.rb +0 -15
  54. data/db/seeds/backup_configs.rb +0 -140
  55. data/lib/generators/rails_nexus/backup_generator.rb +0 -70
  56. data/lib/generators/rails_nexus/templates/backup/backup_helper.sh +0 -152
  57. data/lib/generators/rails_nexus/templates/backup/config.rb +0 -27
  58. data/lib/generators/rails_nexus/templates/backup/models/daily_backup.rb +0 -24
  59. data/lib/generators/rails_nexus/templates/backup/models/full_backup.rb +0 -35
  60. data/lib/generators/rails_nexus/templates/backup/models/sync_backup.rb +0 -43
  61. data/lib/generators/rails_nexus/templates/backup/mysql-config/db_config.cnf +0 -15
  62. data/lib/generators/rails_nexus/templates/backup/schedule.rb +0 -28
@@ -1,8 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "net/http"
4
- require "uri"
5
3
  require "json"
4
+ require "rails_nexus/webhook_client"
6
5
 
7
6
  module RailsNexus
8
7
  module Notifications
@@ -28,28 +27,36 @@ module RailsNexus
28
27
  config.webhooks.each do |url|
29
28
  deliver_webhook(url, payload, config)
30
29
  rescue StandardError => e
31
- Rails.logger.error("[RailsNexus] Webhook failed for #{url}: #{e.message}")
32
- log_webhook_delivery(url: url, payload: payload, error: e.message, event_type: "exception.logged")
30
+ Rails.logger.error("[RailsNexus] Webhook delivery failed: #{e.class}")
31
+ log_webhook_delivery(
32
+ url: RailsNexus::WebhookClient.redacted_url(url),
33
+ payload: payload,
34
+ error: "Webhook delivery failed",
35
+ event_type: "exception.logged"
36
+ )
33
37
  end
34
38
  end
35
39
 
36
40
  def deliver_webhook(url, payload, config)
37
- uri = URI(url)
38
-
39
- http = Net::HTTP.new(uri.host, uri.port)
40
- http.use_ssl = uri.scheme == "https"
41
- http.open_timeout = config.webhook_timeout
42
- http.read_timeout = config.webhook_timeout
43
-
44
- request = Net::HTTP::Post.new(uri)
45
- request["Content-Type"] = "application/json"
46
- config.webhook_headers.each { |k, v| request[k] = v }
47
- request.body = payload.to_json
48
-
49
- response = http.request(request)
50
-
51
- unless response.is_a?(Net::HTTPSuccess)
52
- Rails.logger.error("[RailsNexus] Webhook #{url} returned #{response.code}")
41
+ logged_url = RailsNexus::WebhookClient.redacted_url(url)
42
+ result = RailsNexus::WebhookClient.deliver(
43
+ url: url,
44
+ payload: payload,
45
+ headers: config.webhook_headers,
46
+ timeout: config.webhook_timeout
47
+ )
48
+
49
+ if result[:success]
50
+ log_webhook_delivery(
51
+ url: logged_url,
52
+ payload: payload,
53
+ status_code: result[:status_code],
54
+ response_body: result[:body],
55
+ event_type: "exception.logged"
56
+ )
57
+ else
58
+ Rails.logger.error("[RailsNexus] Webhook delivery failed: #{result[:error]}")
59
+ log_webhook_delivery(url: logged_url, payload: payload, error: result[:error], event_type: "exception.logged")
53
60
  end
54
61
  end
55
62
 
@@ -1,3 +1,3 @@
1
1
  module RailsNexus
2
- VERSION = "2.1.0"
2
+ VERSION = "2.1.3"
3
3
  end
@@ -0,0 +1,151 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ipaddr"
4
+ require "json"
5
+ require "net/http"
6
+ require "openssl"
7
+ require "socket"
8
+ require "uri"
9
+
10
+ module RailsNexus
11
+ class WebhookClient
12
+ class ValidationError < StandardError; end
13
+
14
+ BLOCKED_NETWORKS = %w[
15
+ 0.0.0.0/8 10.0.0.0/8 100.64.0.0/10 127.0.0.0/8 169.254.0.0/16
16
+ 172.16.0.0/12 192.0.0.0/24 192.0.2.0/24 192.168.0.0/16
17
+ 198.18.0.0/15 198.51.100.0/24 203.0.113.0/24 224.0.0.0/4 240.0.0.0/4
18
+ ::/128 ::1/128 ::ffff:0:0/96 100::/64 2001:db8::/32 fc00::/7 fe80::/10 ff00::/8
19
+ ].map { |network| IPAddr.new(network) }.freeze
20
+
21
+ def self.deliver(url:, payload:, headers: {}, timeout: nil)
22
+ new(url: url, payload: payload, headers: headers, timeout: timeout).deliver
23
+ end
24
+
25
+ def self.redacted_url(url)
26
+ uri = URI.parse(url.to_s)
27
+ return "invalid-webhook-url" if uri.host.blank?
28
+
29
+ port = uri.port && uri.port != uri.default_port ? ":#{uri.port}" : ""
30
+ "#{uri.scheme}://#{uri.host}#{port}/[REDACTED]"
31
+ rescue URI::InvalidURIError
32
+ "invalid-webhook-url"
33
+ end
34
+
35
+ def initialize(url:, payload:, headers: {}, timeout: nil, resolver: nil, http_factory: nil)
36
+ @url = url.to_s
37
+ @payload = payload
38
+ @headers = headers || {}
39
+ @timeout = Integer(timeout || RailsNexus.configuration.webhook_timeout || 5)
40
+ @resolver = resolver || method(:resolve_addresses)
41
+ @http_factory = http_factory || ->(host, port) { Net::HTTP.new(host, port) }
42
+ end
43
+
44
+ def deliver
45
+ started_at = Process.clock_gettime(Process::CLOCK_MONOTONIC)
46
+ uri, address = validated_destination
47
+ http = build_http(uri, address)
48
+ response = http.request(build_request(uri))
49
+ status = response.code.to_i
50
+ duration = Process.clock_gettime(Process::CLOCK_MONOTONIC) - started_at
51
+
52
+ if status.between?(300, 399)
53
+ return failure("Webhook redirects are not allowed", status_code: response.code, duration: duration)
54
+ end
55
+
56
+ {
57
+ success: status.between?(200, 299),
58
+ status_code: response.code,
59
+ body: response.body.to_s.truncate(500),
60
+ duration: duration.round(3),
61
+ error: status.between?(200, 299) ? nil : "Webhook returned HTTP #{status}"
62
+ }
63
+ rescue ValidationError => error
64
+ failure(error.message)
65
+ rescue StandardError
66
+ failure("Webhook delivery failed")
67
+ end
68
+
69
+ private
70
+
71
+ def validated_destination
72
+ uri = URI.parse(@url)
73
+ allowed_schemes = ["https"]
74
+ if Rails.env.development? && RailsNexus.configuration.webhook_allow_http_in_development
75
+ allowed_schemes << "http"
76
+ end
77
+
78
+ raise ValidationError, "Webhook URL must use HTTPS" unless allowed_schemes.include?(uri.scheme)
79
+ raise ValidationError, "Webhook URL must include a hostname" if uri.host.blank?
80
+ raise ValidationError, "Webhook URL credentials are not allowed" if uri.userinfo.present?
81
+ validate_host_policy!(uri.host)
82
+
83
+ addresses = Array(@resolver.call(uri.host)).map { |address| IPAddr.new(address.to_s) }.uniq
84
+ raise ValidationError, "Webhook host could not be resolved" if addresses.empty?
85
+ raise ValidationError, "Webhook destination is not publicly routable" if addresses.any? { |address| blocked_address?(address) }
86
+
87
+ [uri, addresses.first.to_s]
88
+ rescue URI::InvalidURIError, IPAddr::InvalidAddressError
89
+ raise ValidationError, "Webhook URL is invalid"
90
+ rescue SocketError
91
+ raise ValidationError, "Webhook host could not be resolved"
92
+ end
93
+
94
+ def resolve_addresses(host)
95
+ Addrinfo.getaddrinfo(host, nil, :UNSPEC, :STREAM).map(&:ip_address)
96
+ end
97
+
98
+ def blocked_address?(address)
99
+ BLOCKED_NETWORKS.any? { |network| network.include?(address) }
100
+ end
101
+
102
+ def validate_host_policy!(host)
103
+ denied = Array(RailsNexus.configuration.webhook_denied_hosts)
104
+ allowed = Array(RailsNexus.configuration.webhook_allowed_hosts)
105
+
106
+ raise ValidationError, "Webhook hostname is denied" if denied.any? { |pattern| host_matches?(host, pattern) }
107
+ if allowed.any? && allowed.none? { |pattern| host_matches?(host, pattern) }
108
+ raise ValidationError, "Webhook hostname is not allowed"
109
+ end
110
+ end
111
+
112
+ def host_matches?(host, pattern)
113
+ candidate = pattern.to_s.downcase
114
+ actual = host.to_s.downcase
115
+ return actual.end_with?(candidate.delete_prefix("*")) if candidate.start_with?("*.")
116
+ actual == candidate
117
+ end
118
+
119
+ def build_http(uri, address)
120
+ http = @http_factory.call(uri.host, uri.port)
121
+ http.ipaddr = address
122
+ http.use_ssl = uri.scheme == "https"
123
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER if http.use_ssl?
124
+ http.open_timeout = @timeout
125
+ http.read_timeout = @timeout
126
+ http
127
+ end
128
+
129
+ def build_request(uri)
130
+ request = Net::HTTP::Post.new(uri.request_uri)
131
+ request["Host"] = uri.port == uri.default_port ? uri.host : "#{uri.host}:#{uri.port}"
132
+ request["Content-Type"] = "application/json"
133
+ @headers.each do |name, value|
134
+ validate_header!(name, value)
135
+ request[name.to_s] = value.to_s
136
+ end
137
+ request.body = @payload.to_json
138
+ request
139
+ end
140
+
141
+ def validate_header!(name, value)
142
+ if name.to_s.match?(/[\r\n]/) || value.to_s.match?(/[\r\n]/)
143
+ raise ValidationError, "Webhook header is invalid"
144
+ end
145
+ end
146
+
147
+ def failure(message, status_code: nil, duration: nil)
148
+ { success: false, error: message, status_code: status_code, duration: duration&.round(3) }
149
+ end
150
+ end
151
+ end
data/lib/rails_nexus.rb CHANGED
@@ -1,16 +1,22 @@
1
1
  require "rails"
2
- require "importmap-rails"
2
+ require "active_support/parameter_filter"
3
3
  require "turbo-rails"
4
4
  require "stimulus-rails"
5
5
  require "pagy"
6
6
  require "ipaddr"
7
7
  require "socket"
8
+ require "open3"
8
9
  require "rails_nexus/version"
9
10
  require "rails_nexus/configuration"
10
11
  require "rails_nexus/logger"
12
+ require "rails_nexus/database_adapter"
11
13
  require "rails_nexus/engine"
12
14
 
13
15
  module RailsNexus
16
+ DEFAULT_FILTER_PARAMETERS = %i[
17
+ password passw passwd secret token api_key apikey authorization cookie session
18
+ ].freeze
19
+
14
20
  class << self
15
21
  attr_writer :configuration
16
22
 
@@ -35,6 +41,24 @@ module RailsNexus
35
41
  def logger
36
42
  RailsNexus::Logger
37
43
  end
44
+
45
+ def parameter_filter
46
+ configured = defined?(::Rails) ? ::Rails.application.config.filter_parameters : []
47
+ ActiveSupport::ParameterFilter.new(DEFAULT_FILTER_PARAMETERS + Array(configured))
48
+ end
49
+
50
+ def filter_sensitive_data(value)
51
+ value = value.to_unsafe_h if value.respond_to?(:to_unsafe_h)
52
+
53
+ case value
54
+ when Hash
55
+ parameter_filter.filter(value)
56
+ when Array
57
+ value.map { |entry| filter_sensitive_data(entry) }
58
+ else
59
+ value
60
+ end
61
+ end
38
62
  end
39
63
 
40
64
  # Copyright (c) 2005 Jamis Buck
@@ -78,28 +102,19 @@ module RailsNexus
78
102
 
79
103
  # we log the exception and raise it again, for the normal handling.
80
104
  def log_exception_handler(exception)
81
- log_exception(exception)
105
+ log_exception(exception) if exception.is_a?(StandardError)
82
106
  raise exception
83
107
  end
84
108
 
85
109
  def rescue_action(exception)
86
110
  status = response_code_for_rescue(exception)
87
- log_exception(exception) if status != :not_found
111
+ log_exception(exception) if exception.is_a?(StandardError) && status != :not_found
88
112
  super
89
113
  end
90
114
 
91
- def filter_sub_parameters(params, rails_filter_parameters)
92
- params.each do |key, value|
93
- if(value.class != Hash and value.class != ActiveSupport::HashWithIndifferentAccess)
94
- params[key] = '[FILTERED]' if rails_filter_parameters.include?(key.to_sym)
95
- else
96
- params[key] = filter_sub_parameters(value, rails_filter_parameters)
97
- end
98
- end
99
- params
100
- end
101
-
102
115
  def log_exception(exception)
116
+ return unless exception.is_a?(StandardError)
117
+
103
118
  # Support both the legacy class_attribute and the new configuration DSL
104
119
  deliverer = if self.class.exception_data
105
120
  self.class.exception_data
@@ -113,15 +128,7 @@ module RailsNexus
113
128
  when Proc then deliverer.call(self)
114
129
  end
115
130
 
116
- rails_filter_parameters = defined?(::Rails) ? ::Rails.application.config.filter_parameters : []
117
-
118
- self.request.parameters.each do |key, value|
119
- if(value.class != Hash and value.class != ActiveSupport::HashWithIndifferentAccess)
120
- self.request.parameters[key] = '[FILTERED]' if rails_filter_parameters.include?(key.to_sym)
121
- else
122
- self.request.parameters[key] = filter_sub_parameters(value, rails_filter_parameters)
123
- end
124
- end if rails_filter_parameters.any?
131
+ data = RailsNexus.filter_sensitive_data(data || {})
125
132
 
126
133
  # Log with structured logger
127
134
  RailsNexus::Logger.error(exception, controller: self, extra: data)
@@ -131,3 +138,10 @@ module RailsNexus
131
138
  end
132
139
  end
133
140
  end
141
+
142
+ # Compatibility for applications that integrated the exception concern under
143
+ # the pre-RailsNexus namespace. New integrations should use
144
+ # RailsNexus::ExceptionLoggable.
145
+ module RailsOps
146
+ ExceptionLoggable = RailsNexus::ExceptionLoggable unless const_defined?(:ExceptionLoggable, false)
147
+ end
@@ -228,84 +228,4 @@ namespace :rails_nexus do
228
228
  puts "✓ Deleted #{count} webhook delivery records older than #{days} days"
229
229
  end
230
230
 
231
- # ─── Backup Tasks ──────────────────────────────────────────────
232
-
233
- desc "Run a specific backup by name: rails_nexus:backup[daily_backup]"
234
- task :backup, [:name] => :environment do |_t, args|
235
- name = args[:name]
236
- if name.blank?
237
- puts "Usage: rake rails_nexus:backup[config_name]"
238
- puts "Available configs:"
239
- RailsNexus::BackupConfig.enabled.pluck(:name).each { |n| puts " - #{n}" }
240
- next
241
- end
242
-
243
- result = RailsNexus::BackupRunner.run(name)
244
- if result[:success]
245
- puts "✓ Backup "#{name}" completed successfully (#{result[:record].duration_human})"
246
- else
247
- puts "✗ Backup "#{name}" failed: #{result[:error]}"
248
- exit 1
249
- end
250
- end
251
-
252
- desc "Run all enabled backup configs"
253
- task backup_all: :environment do
254
- results = RailsNexus::BackupRunner.run_all
255
- results.each do |r|
256
- if r[:success]
257
- puts "✓ #{r[:record].config_name} completed"
258
- else
259
- puts "✗ #{r[:record]&.config_name || '?'} failed: #{r[:error]}"
260
- end
261
- end
262
- end
263
-
264
- desc "Run backups matching current cron schedule"
265
- task backup_scheduled: :environment do
266
- results = RailsNexus::BackupRunner.run_scheduled
267
- if results.empty?
268
- puts "No backups scheduled for this time"
269
- else
270
- results.each do |r|
271
- if r[:success]
272
- puts "✓ #{r[:record].config_name} completed"
273
- else
274
- puts "✗ #{r[:record]&.config_name || '?'} failed: #{r[:error]}"
275
- end
276
- end
277
- end
278
- end
279
-
280
- desc "Clean up old backup records and files (default: 30 days)"
281
- task :backup_cleanup, [:days] => :environment do |_t, args|
282
- days = (args[:days] || 30).to_i
283
- count = RailsNexus::Backup.where("started_at < ?", days.days.ago).delete_all
284
- puts "✓ Deleted #{count} backup records older than #{days} days"
285
- end
286
-
287
- desc "List all backup configs and their status"
288
- task backup_list: :environment do
289
- configs = RailsNexus::BackupConfig.order(:name)
290
- if configs.empty?
291
- puts "No backup configs found"
292
- else
293
- configs.each do |c|
294
- status = c.enabled? ? "✓" : "✗"
295
- last = c.recent_backups(limit: 1).first
296
- last_str = last ? "#{last.status} #{last.started_at&.strftime('%b %d %H:%M')}" : "never"
297
- puts "#{status} #{c.name.ljust(20)} #{c.adapter.ljust(12)} #{c.database_name.ljust(20)} last: #{last_str}"
298
- end
299
- end
300
- end
301
-
302
- desc "Seed backup configs from ~/Backup gem models"
303
- task seed_backups: :environment do
304
- seed_file = File.join(RailsNexus::Engine.root, "db", "seeds", "backup_configs.rb")
305
- if File.exist?(seed_file)
306
- load seed_file
307
- else
308
- puts "Seed file not found: #{seed_file}"
309
- end
310
- end
311
231
  end
data/rails_nexus.gemspec CHANGED
@@ -7,7 +7,7 @@ Gem::Specification.new do |spec|
7
7
  spec.email = ["tamiruhailu@gmail.com"]
8
8
  spec.homepage = "https://github.com/tamiru/rails_nexus"
9
9
  spec.summary = "The extensible control plane for Rails applications"
10
- spec.description = "RailsNexus is an extensible operations and administration console for Rails applications. It provides error monitoring, backup management, cron job tracking, server statistics, database health, real-time analytics, workflow management, source code viewing, N+1 query detection, and storm protection. Built with Hotwire, Stimulus, and Tailwind-compatible CSS."
10
+ spec.description = "RailsNexus is an extensible operations and administration console for Rails applications. It provides error monitoring, cron job tracking, server statistics, database health, real-time analytics, workflow management, source code viewing, N+1 query detection, and storm protection. Built with Hotwire, Stimulus, and Tailwind-compatible CSS."
11
11
  spec.metadata["rubygems_mfa_required"] = "true"
12
12
  spec.license = "MIT"
13
13
 
@@ -15,10 +15,12 @@ Gem::Specification.new do |spec|
15
15
  spec.metadata["homepage_uri"] = spec.homepage
16
16
  spec.metadata["source_code_uri"] = "https://github.com/tamiru/rails_nexus/tree/main"
17
17
  spec.metadata["changelog_uri"] = "https://github.com/tamiru/rails_nexus/blob/main/CHANGELOG.md"
18
+ spec.metadata["bug_tracker_uri"] = "https://github.com/tamiru/rails_nexus/issues"
18
19
  spec.metadata["funding_uri"] = "https://github.com/sponsors/tamiru"
19
20
 
20
21
  spec.files = Dir.chdir(File.expand_path(__dir__)) do
21
- Dir["{app,config,db,lib}/**/*", "MIT-LICENSE", "Rakefile", "README.md", "rails_nexus.gemspec"]
22
+ Dir["{app,config,db,lib}/**/*", "CHANGELOG.md", "SECURITY.md", "THIRD_PARTY_NOTICES.md", "MIT-LICENSE", "Rakefile", "README.md", "rails_nexus.gemspec"]
23
+ .reject { |file| file.match?(%r{(?:^|/)(?:\.idea|log|tmp|storage|pkg)(?:/|$)|\.(?:gem|sqlite3|log)\z|Zone\.Identifier\z}) }
22
24
  end
23
25
 
24
26
  spec.required_ruby_version = ">= 3.2.0"
@@ -26,11 +28,8 @@ Gem::Specification.new do |spec|
26
28
  spec.add_dependency "rails", "~> 8.0", ">= 8.0.0"
27
29
  spec.add_dependency "stimulus-rails", "~> 1.3"
28
30
  spec.add_dependency "turbo-rails", "~> 2.0"
29
- spec.add_dependency "importmap-rails", "~> 2.0"
30
31
  spec.add_dependency "pagy", "~> 6.5"
31
32
 
32
33
  spec.add_dependency "ransack", "~> 4.0"
33
34
 
34
- # Note: Backup management requires 'backup' (~> 4.4) and 'whenever' (~> 1.1)
35
- # gems to be added to your host application's Gemfile.
36
35
  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.1.0
4
+ version: 2.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tamiru Hailu
@@ -57,20 +57,6 @@ dependencies:
57
57
  - - "~>"
58
58
  - !ruby/object:Gem::Version
59
59
  version: '2.0'
60
- - !ruby/object:Gem::Dependency
61
- name: importmap-rails
62
- requirement: !ruby/object:Gem::Requirement
63
- requirements:
64
- - - "~>"
65
- - !ruby/object:Gem::Version
66
- version: '2.0'
67
- type: :runtime
68
- prerelease: false
69
- version_requirements: !ruby/object:Gem::Requirement
70
- requirements:
71
- - - "~>"
72
- - !ruby/object:Gem::Version
73
- version: '2.0'
74
60
  - !ruby/object:Gem::Dependency
75
61
  name: pagy
76
62
  requirement: !ruby/object:Gem::Requirement
@@ -100,25 +86,28 @@ dependencies:
100
86
  - !ruby/object:Gem::Version
101
87
  version: '4.0'
102
88
  description: RailsNexus is an extensible operations and administration console for
103
- Rails applications. It provides error monitoring, backup management, cron job tracking,
104
- server statistics, database health, real-time analytics, workflow management, source
105
- code viewing, N+1 query detection, and storm protection. Built with Hotwire, Stimulus,
106
- and Tailwind-compatible CSS.
89
+ Rails applications. It provides error monitoring, cron job tracking, server statistics,
90
+ database health, real-time analytics, workflow management, source code viewing,
91
+ N+1 query detection, and storm protection. Built with Hotwire, Stimulus, and Tailwind-compatible
92
+ CSS.
107
93
  email:
108
94
  - tamiruhailu@gmail.com
109
95
  executables: []
110
96
  extensions: []
111
97
  extra_rdoc_files: []
112
98
  files:
99
+ - CHANGELOG.md
113
100
  - MIT-LICENSE
114
101
  - README.md
115
102
  - Rakefile
103
+ - SECURITY.md
104
+ - THIRD_PARTY_NOTICES.md
116
105
  - app/assets/config/rails_nexus_manifest.js
106
+ - app/assets/javascripts/rails_nexus/application.js
117
107
  - app/assets/javascripts/rails_nexus/controllers.js
118
108
  - app/assets/stylesheets/rails_nexus/application.css
119
109
  - app/controllers/rails_nexus/analytics_controller.rb
120
110
  - app/controllers/rails_nexus/application_controller.rb
121
- - app/controllers/rails_nexus/backup_controller.rb
122
111
  - app/controllers/rails_nexus/cron_jobs_controller.rb
123
112
  - app/controllers/rails_nexus/database_health_controller.rb
124
113
  - app/controllers/rails_nexus/logged_exceptions_controller.rb
@@ -136,28 +125,17 @@ files:
136
125
  - app/javascript/controllers/rails_nexus_theme_controller.js
137
126
  - app/javascript/rails_nexus/application.js
138
127
  - app/jobs/rails_nexus/application_job.rb
139
- - app/jobs/rails_nexus/backup_job.rb
140
128
  - app/mailers/rails_nexus/application_mailer.rb
141
129
  - app/models/rails_nexus/application_record.rb
142
- - app/models/rails_nexus/backup.rb
143
- - app/models/rails_nexus/backup_config.rb
144
130
  - app/models/rails_nexus/base_record.rb
145
131
  - app/models/rails_nexus/comment.rb
146
132
  - app/models/rails_nexus/cron_job.rb
147
133
  - app/models/rails_nexus/logged_exception.rb
148
134
  - app/models/rails_nexus/logged_exception_n1.rb
149
135
  - app/models/rails_nexus/webhook_delivery.rb
150
- - app/services/rails_nexus/backup_runner.rb
151
- - app/services/rails_nexus/backup_service.rb
152
136
  - app/views/layouts/rails_nexus/_sidebar_navigation.html.erb
153
137
  - app/views/layouts/rails_nexus/application.html.erb
154
138
  - app/views/rails_nexus/analytics/index.html.erb
155
- - app/views/rails_nexus/backup/_form.html.erb
156
- - app/views/rails_nexus/backup/config_history.html.erb
157
- - app/views/rails_nexus/backup/edit.html.erb
158
- - app/views/rails_nexus/backup/history.html.erb
159
- - app/views/rails_nexus/backup/index.html.erb
160
- - app/views/rails_nexus/backup/new.html.erb
161
139
  - app/views/rails_nexus/cron_jobs/index.html.erb
162
140
  - app/views/rails_nexus/database_health/index.html.erb
163
141
  - app/views/rails_nexus/logged_exceptions/_comments_list.html.erb
@@ -178,22 +156,12 @@ files:
178
156
  - app/views/rails_nexus/n1_patterns/index.html.erb
179
157
  - app/views/rails_nexus/settings/index.html.erb
180
158
  - app/views/rails_nexus/stats/index.html.erb
181
- - config/importmap.rb
182
159
  - config/initializers/date_formats.rb
183
160
  - config/locales/en.yml
184
161
  - config/routes.rb
185
- - db/seeds/backup_configs.rb
186
- - lib/generators/rails_nexus/backup_generator.rb
187
162
  - lib/generators/rails_nexus/customize_generator.rb
188
163
  - lib/generators/rails_nexus/install_generator.rb
189
164
  - lib/generators/rails_nexus/templates/INSTALL.md
190
- - lib/generators/rails_nexus/templates/backup/backup_helper.sh
191
- - lib/generators/rails_nexus/templates/backup/config.rb
192
- - lib/generators/rails_nexus/templates/backup/models/daily_backup.rb
193
- - lib/generators/rails_nexus/templates/backup/models/full_backup.rb
194
- - lib/generators/rails_nexus/templates/backup/models/sync_backup.rb
195
- - lib/generators/rails_nexus/templates/backup/mysql-config/db_config.cnf
196
- - lib/generators/rails_nexus/templates/backup/schedule.rb
197
165
  - lib/generators/rails_nexus/templates/javascript/controllers/rails_nexus_controller.js
198
166
  - lib/generators/rails_nexus/templates/javascript/controllers/rails_nexus_detail_controller.js
199
167
  - lib/generators/rails_nexus/templates/javascript/controllers/rails_nexus_sidebar_controller.js
@@ -208,12 +176,14 @@ files:
208
176
  - lib/rails_nexus/breadcrumbs.rb
209
177
  - lib/rails_nexus/cleanup.rb
210
178
  - lib/rails_nexus/configuration.rb
179
+ - lib/rails_nexus/database_adapter.rb
211
180
  - lib/rails_nexus/engine.rb
212
181
  - lib/rails_nexus/logger.rb
213
182
  - lib/rails_nexus/notifications.rb
214
183
  - lib/rails_nexus/ransack_config.rb
215
184
  - lib/rails_nexus/storm_protection.rb
216
185
  - lib/rails_nexus/version.rb
186
+ - lib/rails_nexus/webhook_client.rb
217
187
  - lib/tasks/rails_nexus.rake
218
188
  - lib/tasks/rails_nexus_tasks.rake
219
189
  - rails_nexus.gemspec
@@ -226,6 +196,7 @@ metadata:
226
196
  homepage_uri: https://github.com/tamiru/rails_nexus
227
197
  source_code_uri: https://github.com/tamiru/rails_nexus/tree/main
228
198
  changelog_uri: https://github.com/tamiru/rails_nexus/blob/main/CHANGELOG.md
199
+ bug_tracker_uri: https://github.com/tamiru/rails_nexus/issues
229
200
  funding_uri: https://github.com/sponsors/tamiru
230
201
  rdoc_options: []
231
202
  require_paths: