Lots of updates

This commit is contained in:
Dan Milne
2025-11-11 16:54:52 +11:00
parent 26216da9ca
commit cc8213f87a
41 changed files with 1463 additions and 614 deletions

View File

@@ -77,4 +77,6 @@ Rails.application.configure do
# config.generators.apply_rubocop_autocorrect_after_generate!
config.active_job.queue_adapter = :solid_queue
config.solid_queue.connects_to = { database: { writing: :queue } }
# Don't store finished jobs - we don't need job history, saves DB space
config.solid_queue.preserve_finished_jobs = false
end

View File

@@ -52,6 +52,8 @@ Rails.application.configure do
# Replace the default in-process and non-durable queuing backend for Active Job.
config.active_job.queue_adapter = :solid_queue
config.solid_queue.connects_to = { database: { writing: :queue } }
# Don't store finished jobs - we don't need job history, saves DB space
config.solid_queue.preserve_finished_jobs = false
# Ignore bad email addresses and do not raise email delivery errors.
# Set this to true and configure the email server for immediate delivery to raise delivery errors.

View File

@@ -5,3 +5,7 @@ pin "@hotwired/turbo-rails", to: "turbo.min.js"
pin "@hotwired/stimulus", to: "stimulus.min.js"
pin "@hotwired/stimulus-loading", to: "stimulus-loading.js"
pin_all_from "app/javascript/controllers", under: "controllers"
# Tom Select for enhanced multi-select
pin "tom-select", to: "https://cdn.jsdelivr.net/npm/tom-select@2.3.1/dist/js/tom-select.complete.min.js"
pin "tom-select-css", to: "https://cdn.jsdelivr.net/npm/tom-select@2.3.1/dist/css/tom-select.css"

View File

@@ -0,0 +1,156 @@
# frozen_string_literal: true
# Sentry configuration for error tracking and performance monitoring
# Only initializes if SENTRY_DSN is configured
return unless ENV['SENTRY_DSN'].present?
require 'sentry-rails'
Sentry.init do |config|
config.dsn = ENV['SENTRY_DSN']
# Configure sampling for production (lower in production, higher in staging)
config.traces_sample_rate = case Rails.env
when 'production' then ENV.fetch('SENTRY_TRACES_SAMPLE_RATE', '0.05').to_f
when 'staging' then ENV.fetch('SENTRY_TRACES_SAMPLE_RATE', '0.2').to_f
else ENV.fetch('SENTRY_TRACES_SAMPLE_RATE', '0.1').to_f
end
# Enable breadcrumbs for better debugging
config.breadcrumbs_logger = [:active_support_logger, :http_logger]
# Send PII data (like IPs) to Sentry for debugging (disable in production if needed)
config.send_default_pii = ENV.fetch('SENTRY_SEND_PII', 'false') == 'true'
# Set environment
config.environment = Rails.env
# Configure release info from Docker tag or Git
if ENV['GIT_COMMIT_SHA']
config.release = ENV['GIT_COMMIT_SHA'][0..7]
elsif ENV['APP_VERSION']
config.release = ENV['APP_VERSION']
end
# Set server name for multi-instance environments
config.server_name = ENV.fetch('SERVER_NAME', 'baffle-agent')
# Filter out certain errors to reduce noise and add tags
config.before_send = lambda do |event, hint|
# Filter out 404 errors and other expected HTTP errors
if event.contexts.dig(:response, :status_code) == 404
nil
# Filter out validation errors in development
elsif Rails.env.development? && event.exception&.message&.include?("Validation failed")
nil
# Filter out specific noisy exceptions
elsif %w[ActionController::RoutingError
ActionController::InvalidAuthenticityToken
ActionController::UnknownFormat
ActionDispatch::Http::Parameters::ParseError].include?(event.exception&.class&.name)
nil
else
# Add tags for better filtering in Sentry
event.tags.merge!({
ruby_version: RUBY_VERSION,
rails_version: Rails.version,
environment: Rails.env
})
event
end
end
# Configure exception class exclusion
config.excluded_exceptions += [
'ActionController::RoutingError',
'ActionController::InvalidAuthenticityToken',
'CGI::Session::CookieStore::TamperedWithCookie',
'ActionController::UnknownFormat',
'ActionDispatch::Http::Parameters::ParseError',
'Mongoid::Errors::DocumentNotFound'
]
end
# SolidQueue monitoring will be automatically handled by sentry-solid_queue gem
# Add correlation ID to Sentry context
ActiveSupport::Notifications.subscribe('action_controller.process_action') do |name, start, finish, id, payload|
controller = payload[:controller]
action = payload[:action]
request_id = payload[:request]&.request_id
if controller && action && request_id
Sentry.set_context(:request, {
correlation_id: request_id,
controller: controller.controller_name,
action: action.action_name,
ip: request&.remote_ip
})
end
end
# Add ActiveJob context to all job transactions
ActiveSupport::Notifications.subscribe('perform.active_job') do |name, start, finish, id, payload|
job = payload[:job]
Sentry.configure_scope do |scope|
scope.set_tag(:job_class, job.class.name)
scope.set_tag(:job_queue, job.queue_name)
scope.set_tag(:job_id, job.job_id)
scope.set_context(:job, {
job_id: job.job_id,
job_class: job.class.name,
queue_name: job.queue_name,
arguments: job.arguments.to_s,
enqueued_at: job.enqueued_at,
executions: job.executions
})
end
end
# Monitor SolidQueue job failures
ActiveSupport::Notifications.subscribe('solid_queue.error') do |name, start, finish, id, payload|
job = payload[:job]
error = payload[:error]
Sentry.with_scope do |scope|
scope.set_tag(:job_class, job.class_name)
scope.set_tag(:job_queue, job.queue_name)
scope.set_context(:job, {
job_id: job.active_job_id,
arguments: job.arguments.to_s,
queue_name: job.queue_name,
created_at: job.created_at
})
scope.set_context(:error, {
error_class: error.class.name,
error_message: error.message
})
Sentry.capture_exception(error)
end
end
# Set user context when available
if defined?(Current) && Current.user
Sentry.set_user(id: Current.user.id, email: Current.user.email)
end
# Add application-specific context
app_version = begin
File.read(Rails.root.join('VERSION')).strip
rescue
ENV['APP_VERSION'] || ENV['GIT_COMMIT_SHA']&.[](0..7) || 'unknown'
end
Sentry.set_context('application', {
name: 'BaffleHub',
version: app_version,
environment: Rails.env,
database: ActiveRecord::Base.connection.adapter_name,
queue_adapter: Rails.application.config.active_job.queue_adapter
})
Rails.logger.info "Sentry configured for environment: #{Rails.env}"

View File

@@ -9,7 +9,11 @@
# priority: 2
# schedule: at 5am every day
production:
clear_solid_queue_finished_jobs:
command: "SolidQueue::Job.clear_finished_in_batches(sleep_between_batches: 0.3)"
schedule: every hour at minute 12
# No recurring tasks configured yet
# (previously had clear_solid_queue_finished_jobs, but now preserve_finished_jobs: false in queue.yml)
# Clean up failed jobs older than 1 day
cleanup_failed_jobs:
command: "SolidQueue::FailedExecution.where('created_at < ?', 1.day.ago).delete_all"
queue: background
schedule: every 6 hours

View File

@@ -11,6 +11,13 @@ Rails.application.routes.draw do
# Admin user management (admin only)
resources :users, only: [:index, :show, :edit, :update]
# Settings management (admin only)
resources :settings, only: [:index] do
collection do
patch :update
end
end
# DSN management (admin only)
resources :dsns do
member do
@@ -44,7 +51,7 @@ Rails.application.routes.draw do
root "analytics#index"
# Event management
resources :events, only: [:index]
resources :events, only: [:index, :show]
# Network range management
resources :network_ranges, only: [:index, :show, :new, :create, :edit, :update, :destroy] do
@@ -79,4 +86,11 @@ Rails.application.routes.draw do
post :create_country
end
end
# GeoLite2 data import management (admin only)
resources :data_imports, only: [:index, :new, :create, :show, :destroy] do
member do
get :progress
end
end
end

View File

@@ -4,7 +4,7 @@ test:
local:
service: Disk
root: <%= Rails.root.join("storage") %>
root: <%= Rails.root.join("storage", "uploads") %>
# Use bin/rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key)
# amazon:

13
config/tailwind.config.js Normal file
View File

@@ -0,0 +1,13 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
'./app/helpers/**/*.rb',
'./app/javascript/**/*.js',
'./app/views/**/*.erb',
'./app/views/**/*.html.erb'
],
theme: {
extend: {},
},
plugins: [],
}