vert-core 1.0.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 (40) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +14 -0
  3. data/README.md +126 -0
  4. data/lib/vert/authorization/controller_methods.rb +84 -0
  5. data/lib/vert/authorization/dynamic_policy.rb +156 -0
  6. data/lib/vert/authorization/permission_resolver.rb +253 -0
  7. data/lib/vert/authorization/policy_finder.rb +72 -0
  8. data/lib/vert/clients/document_service_client.rb +104 -0
  9. data/lib/vert/concerns/auditable.rb +24 -0
  10. data/lib/vert/concerns/company_scoped.rb +48 -0
  11. data/lib/vert/concerns/current_attributes.rb +53 -0
  12. data/lib/vert/concerns/document_storeable.rb +180 -0
  13. data/lib/vert/concerns/multi_tenant.rb +45 -0
  14. data/lib/vert/concerns/soft_deletable.rb +46 -0
  15. data/lib/vert/concerns/uuid_primary_key.rb +42 -0
  16. data/lib/vert/configuration.rb +65 -0
  17. data/lib/vert/generators/install_generator.rb +66 -0
  18. data/lib/vert/generators/rls_migration_generator.rb +57 -0
  19. data/lib/vert/generators/templates/application_record.rb.tt +8 -0
  20. data/lib/vert/generators/templates/create_outbox_events.rb.tt +24 -0
  21. data/lib/vert/generators/templates/create_rls_functions.rb.tt +27 -0
  22. data/lib/vert/generators/templates/current.rb.tt +10 -0
  23. data/lib/vert/generators/templates/enable_rls_on_tables.rb.tt +39 -0
  24. data/lib/vert/generators/templates/health_controller.rb.tt +5 -0
  25. data/lib/vert/generators/templates/initializer.rb.tt +39 -0
  26. data/lib/vert/generators/templates/outbox_event.rb.tt +11 -0
  27. data/lib/vert/health/checker.rb +119 -0
  28. data/lib/vert/health/routes.rb +44 -0
  29. data/lib/vert/outbox/event.rb +68 -0
  30. data/lib/vert/outbox/publisher.rb +105 -0
  31. data/lib/vert/outbox/publisher_job.rb +30 -0
  32. data/lib/vert/railtie.rb +54 -0
  33. data/lib/vert/rls/connection_handler.rb +56 -0
  34. data/lib/vert/rls/consumer_context.rb +31 -0
  35. data/lib/vert/rls/context_middleware.rb +37 -0
  36. data/lib/vert/rls/job_context.rb +56 -0
  37. data/lib/vert/version.rb +5 -0
  38. data/lib/vert.rb +58 -0
  39. data/vert.gemspec +43 -0
  40. metadata +223 -0
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Vert
4
+ module Authorization
5
+ class PolicyFinder
6
+ attr_reader :object
7
+
8
+ def initialize(object)
9
+ @object = object
10
+ end
11
+
12
+ def policy
13
+ find_policy || DynamicPolicy
14
+ end
15
+
16
+ def policy!
17
+ policy || raise(Pundit::NotDefinedError, "Unable to find policy for #{object}")
18
+ end
19
+
20
+ def scope
21
+ find_scope || DynamicPolicy::Scope
22
+ end
23
+
24
+ def scope!
25
+ scope || raise(Pundit::NotDefinedError, "Unable to find scope for #{object}")
26
+ end
27
+
28
+ private
29
+
30
+ def find_policy
31
+ specific_policy = "#{model_name}Policy"
32
+ return Object.const_get(specific_policy) if Object.const_defined?(specific_policy)
33
+
34
+ namespaced_policy = "#{model_namespace}::#{model_class_name}Policy"
35
+ return Object.const_get(namespaced_policy) if Object.const_defined?(namespaced_policy)
36
+
37
+ service_policy = "#{service_name}::DynamicPolicy"
38
+ return Object.const_get(service_policy) if Object.const_defined?(service_policy)
39
+
40
+ nil
41
+ rescue NameError
42
+ nil
43
+ end
44
+
45
+ def find_scope
46
+ policy_class = find_policy
47
+ return nil unless policy_class
48
+ policy_class.const_defined?(:Scope) ? policy_class::Scope : nil
49
+ end
50
+
51
+ def model_name
52
+ case object
53
+ when Class then object.name
54
+ when Symbol, String then object.to_s.camelize
55
+ else object.class.name
56
+ end
57
+ end
58
+
59
+ def model_class_name
60
+ model_name.demodulize
61
+ end
62
+
63
+ def model_namespace
64
+ model_name.deconstantize.presence || "App"
65
+ end
66
+
67
+ def service_name
68
+ model_namespace.underscore.split("/").first.camelize
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "net/http"
4
+ require "json"
5
+ require "uri"
6
+ require "base64"
7
+
8
+ module Vert
9
+ module Clients
10
+ class DocumentServiceClient
11
+ attr_reader :base_url, :timeout
12
+
13
+ def initialize(base_url: nil, timeout: 30)
14
+ @base_url = base_url || Vert.config.document_service_url
15
+ @timeout = timeout
16
+ end
17
+
18
+ def upload(resource:, filename:, content:, content_type:, metadata: {})
19
+ uri = URI.parse("#{base_url}/api/v1/objects")
20
+ request = Net::HTTP::Post.new(uri)
21
+ request["Content-Type"] = "application/json"
22
+ add_auth_headers(request)
23
+ request.body = {
24
+ object: {
25
+ resource: resource,
26
+ original_filename: filename,
27
+ content_type: content_type,
28
+ content_base64: Base64.strict_encode64(content.to_s),
29
+ metadata: metadata
30
+ }
31
+ }.to_json
32
+ execute_request(uri, request)
33
+ end
34
+
35
+ def download_url(object_id:, disposition: "inline", expires_in: 3600)
36
+ uri = URI.parse("#{base_url}/api/v1/objects/#{object_id}/download_url")
37
+ uri.query = URI.encode_www_form(disposition: disposition, expires_in: expires_in)
38
+ request = Net::HTTP::Get.new(uri)
39
+ add_auth_headers(request)
40
+ execute_request(uri, request)
41
+ end
42
+
43
+ def download(object_id:)
44
+ result = download_url(object_id: object_id)
45
+ return nil unless result[:success]
46
+ url = result[:data][:url]
47
+ response = Net::HTTP.get_response(URI.parse(url))
48
+ response.body if response.is_a?(Net::HTTPSuccess)
49
+ end
50
+
51
+ def object(object_id)
52
+ uri = URI.parse("#{base_url}/api/v1/objects/#{object_id}")
53
+ request = Net::HTTP::Get.new(uri)
54
+ add_auth_headers(request)
55
+ execute_request(uri, request)
56
+ end
57
+
58
+ def delete_object(object_id)
59
+ uri = URI.parse("#{base_url}/api/v1/objects/#{object_id}")
60
+ request = Net::HTTP::Delete.new(uri)
61
+ add_auth_headers(request)
62
+ execute_request(uri, request)
63
+ end
64
+
65
+ def list_objects(resource: nil, page: 1, per_page: 20)
66
+ uri = URI.parse("#{base_url}/api/v1/objects")
67
+ params = { page: page, per_page: per_page }
68
+ params[:resource] = resource if resource
69
+ uri.query = URI.encode_www_form(params)
70
+ request = Net::HTTP::Get.new(uri)
71
+ add_auth_headers(request)
72
+ execute_request(uri, request)
73
+ end
74
+
75
+ private
76
+
77
+ def execute_request(uri, request)
78
+ http = Net::HTTP.new(uri.host, uri.port)
79
+ http.use_ssl = uri.scheme == "https"
80
+ http.open_timeout = timeout
81
+ http.read_timeout = timeout
82
+ response = http.request(request)
83
+ case response
84
+ when Net::HTTPSuccess
85
+ body = JSON.parse(response.body, symbolize_names: true)
86
+ { success: true, data: body[:data] || body }
87
+ else
88
+ body = (JSON.parse(response.body, symbolize_names: true) rescue {})
89
+ { success: false, error: body[:error] || response.message, status: response.code.to_i }
90
+ end
91
+ rescue StandardError => e
92
+ { success: false, error: e.message }
93
+ end
94
+
95
+ def add_auth_headers(request)
96
+ request["Accept"] = "application/json"
97
+ request["X-Tenant-ID"] = Vert::Current.tenant_id.to_s if Vert::Current.tenant_id
98
+ request["X-Company-ID"] = Vert::Current.company_id.to_s if Vert::Current.company_id
99
+ request["X-User-ID"] = Vert::Current.user_id.to_s if Vert::Current.user_id
100
+ request["X-Request-ID"] = Vert::Current.request_id.to_s if Vert::Current.request_id
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Vert
4
+ module Concerns
5
+ module Auditable
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ before_create :set_created_by
10
+ before_update :set_updated_by
11
+ end
12
+
13
+ private
14
+
15
+ def set_created_by
16
+ self.created_by ||= Vert::Current.user_id if has_attribute?(:created_by)
17
+ end
18
+
19
+ def set_updated_by
20
+ self.updated_by = Vert::Current.user_id if has_attribute?(:updated_by)
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Vert
4
+ module Concerns
5
+ module CompanyScoped
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ validates :company_id, presence: true
10
+ validate :company_belongs_to_tenant, if: -> { tenant_id.present? && company_id.present? }
11
+ default_scope do
12
+ if Vert::Current.company_id.present?
13
+ where(company_id: Vert::Current.company_id)
14
+ else
15
+ all
16
+ end
17
+ end
18
+ before_validation :set_company_id, on: :create
19
+ end
20
+
21
+ class_methods do
22
+ def for_company(company_id)
23
+ unscope(where: :company_id).where(company_id: company_id)
24
+ end
25
+
26
+ def all_companies
27
+ unscope(where: :company_id)
28
+ end
29
+
30
+ def belongs_to_current_company?(id)
31
+ exists?(id: id)
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ def set_company_id
38
+ self.company_id ||= Vert::Current.company_id
39
+ end
40
+
41
+ def company_belongs_to_tenant
42
+ return unless defined?(Company)
43
+ return if Company.unscoped.exists?(id: company_id, tenant_id: tenant_id)
44
+ errors.add(:company_id, "does not belong to the current tenant")
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Vert
4
+ module Concerns
5
+ # CurrentAttributes - Thread-safe request context
6
+ class Current < ActiveSupport::CurrentAttributes
7
+ attribute :tenant_id, :company_id, :user_id, :request_id, :rls_configured
8
+
9
+ def self.reset_all
10
+ reset
11
+ end
12
+
13
+ def self.set_context(tenant_id:, user_id: nil, company_id: nil, request_id: nil)
14
+ self.tenant_id = tenant_id
15
+ self.user_id = user_id
16
+ self.company_id = company_id
17
+ self.request_id = request_id || SecureRandom.uuid
18
+ end
19
+
20
+ def self.serialize
21
+ { tenant_id: tenant_id, user_id: user_id, company_id: company_id, request_id: request_id }
22
+ end
23
+
24
+ def self.deserialize(hash)
25
+ return unless hash.is_a?(Hash)
26
+ set_context(
27
+ tenant_id: hash[:tenant_id] || hash["tenant_id"],
28
+ user_id: hash[:user_id] || hash["user_id"],
29
+ company_id: hash[:company_id] || hash["company_id"],
30
+ request_id: hash[:request_id] || hash["request_id"]
31
+ )
32
+ end
33
+
34
+ def self.tenant_set?
35
+ tenant_id.present?
36
+ end
37
+
38
+ def self.company_set?
39
+ company_id.present?
40
+ end
41
+
42
+ def self.require_tenant!
43
+ raise Vert::TenantNotSetError, "Tenant context not set" unless tenant_set?
44
+ end
45
+
46
+ def self.require_company!
47
+ raise Vert::CompanyNotSetError, "Company context not set" unless company_set?
48
+ end
49
+ end
50
+ end
51
+
52
+ Current = Concerns::Current
53
+ end
@@ -0,0 +1,180 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Vert
4
+ module Concerns
5
+ module DocumentStoreable
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ class_attribute :document_attachments, default: {}
10
+ end
11
+
12
+ class_methods do
13
+ def has_document(name, resource:, content_type: nil)
14
+ document_attachments[name] = { resource: resource, content_type: content_type }
15
+
16
+ define_method(name) do
17
+ object_id = send("#{name}_object_id")
18
+ return nil unless object_id.present?
19
+ @document_cache ||= {}
20
+ @document_cache[name] ||= Vert::Concerns::DocumentStoreable::DocumentAttachment.new(
21
+ object_id: object_id,
22
+ resource: document_attachments[name][:resource],
23
+ owner: self
24
+ )
25
+ end
26
+
27
+ define_method("#{name}=") do |value|
28
+ return if value.nil?
29
+ result = attach_document(name, value)
30
+ if result[:success]
31
+ send("#{name}_object_id=", result[:data][:id])
32
+ @document_cache&.delete(name)
33
+ else
34
+ errors.add(name, "upload failed: #{result[:error]}")
35
+ end
36
+ end
37
+
38
+ define_method("attach_#{name}") do |content:, filename:, content_type: nil|
39
+ config = self.class.document_attachments[name]
40
+ ct = content_type || config[:content_type] || detect_content_type(filename)
41
+ result = document_service_client.upload(
42
+ resource: config[:resource],
43
+ filename: filename,
44
+ content: content,
45
+ content_type: ct,
46
+ metadata: document_metadata(name)
47
+ )
48
+ if result[:success]
49
+ send("#{name}_object_id=", result[:data][:id])
50
+ @document_cache&.delete(name)
51
+ else
52
+ errors.add(name, "upload failed: #{result[:error]}")
53
+ end
54
+ result
55
+ end
56
+
57
+ define_method("#{name}_attached?") { send("#{name}_object_id").present? }
58
+
59
+ define_method("purge_#{name}") do
60
+ object_id = send("#{name}_object_id")
61
+ return true unless object_id.present?
62
+ result = document_service_client.delete_object(object_id)
63
+ if result[:success]
64
+ send("#{name}_object_id=", nil)
65
+ @document_cache&.delete(name)
66
+ true
67
+ else
68
+ false
69
+ end
70
+ end
71
+ end
72
+ end
73
+
74
+ private
75
+
76
+ def document_service_client
77
+ @document_service_client ||= Vert::Clients::DocumentServiceClient.new
78
+ end
79
+
80
+ def attach_document(name, value)
81
+ config = self.class.document_attachments[name]
82
+ case value
83
+ when ActionDispatch::Http::UploadedFile, Rack::Test::UploadedFile
84
+ document_service_client.upload(
85
+ resource: config[:resource],
86
+ filename: value.original_filename,
87
+ content: value.read,
88
+ content_type: value.content_type || config[:content_type],
89
+ metadata: document_metadata(name)
90
+ )
91
+ when Hash
92
+ document_service_client.upload(
93
+ resource: config[:resource],
94
+ filename: value[:filename],
95
+ content: value[:content],
96
+ content_type: value[:content_type] || config[:content_type],
97
+ metadata: document_metadata(name)
98
+ )
99
+ when String
100
+ document_service_client.upload(
101
+ resource: config[:resource],
102
+ filename: "#{name}_#{id || SecureRandom.uuid}.bin",
103
+ content: value,
104
+ content_type: config[:content_type] || "application/octet-stream",
105
+ metadata: document_metadata(name)
106
+ )
107
+ else
108
+ { success: false, error: "Invalid value type for document" }
109
+ end
110
+ end
111
+
112
+ def document_metadata(name)
113
+ metadata = { owner_type: self.class.name, owner_id: id, field_name: name.to_s }
114
+ metadata[:tenant_id] = tenant_id if respond_to?(:tenant_id)
115
+ metadata[:company_id] = company_id if respond_to?(:company_id)
116
+ metadata
117
+ end
118
+
119
+ def detect_content_type(filename)
120
+ ext = File.extname(filename).downcase
121
+ CONTENT_TYPES[ext] || "application/octet-stream"
122
+ end
123
+
124
+ CONTENT_TYPES = {
125
+ ".xml" => "application/xml", ".pdf" => "application/pdf",
126
+ ".png" => "image/png", ".jpg" => "image/jpeg", ".jpeg" => "image/jpeg", ".gif" => "image/gif",
127
+ ".csv" => "text/csv", ".xlsx" => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
128
+ ".xls" => "application/vnd.ms-excel", ".doc" => "application/msword",
129
+ ".docx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
130
+ ".zip" => "application/zip", ".txt" => "text/plain", ".json" => "application/json"
131
+ }.freeze
132
+ end
133
+
134
+ class DocumentStoreable::DocumentAttachment
135
+ attr_reader :storage_object_id, :resource, :owner
136
+
137
+ def initialize(object_id:, resource:, owner:)
138
+ @storage_object_id = object_id
139
+ @resource = resource
140
+ @owner = owner
141
+ end
142
+
143
+ def url(disposition: "inline", expires_in: 3600)
144
+ result = client.download_url(object_id: storage_object_id, disposition: disposition, expires_in: expires_in)
145
+ result[:success] ? result[:data][:url] : nil
146
+ end
147
+
148
+ def download
149
+ client.download(object_id: storage_object_id)
150
+ end
151
+
152
+ def details
153
+ result = client.object(storage_object_id)
154
+ result[:success] ? result[:data] : nil
155
+ end
156
+
157
+ def filename
158
+ details&.dig(:original_filename)
159
+ end
160
+
161
+ def content_type
162
+ details&.dig(:mime_type)
163
+ end
164
+
165
+ def byte_size
166
+ details&.dig(:size)
167
+ end
168
+
169
+ def attached?
170
+ storage_object_id.present?
171
+ end
172
+
173
+ private
174
+
175
+ def client
176
+ @client ||= Vert::Clients::DocumentServiceClient.new
177
+ end
178
+ end
179
+ end
180
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Vert
4
+ module Concerns
5
+ module MultiTenant
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ validates :tenant_id, presence: true, if: :require_tenant_id?
10
+ default_scope do
11
+ if Vert::Current.tenant_id.present?
12
+ where(tenant_id: Vert::Current.tenant_id)
13
+ else
14
+ all
15
+ end
16
+ end
17
+ before_validation :set_tenant_id, on: :create
18
+ end
19
+
20
+ class_methods do
21
+ def unscoped_for_tenant(tenant_id)
22
+ unscoped.where(tenant_id: tenant_id)
23
+ end
24
+
25
+ def all_tenants
26
+ unscoped
27
+ end
28
+
29
+ def belongs_to_current_tenant?(id)
30
+ exists?(id: id)
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ def require_tenant_id?
37
+ true
38
+ end
39
+
40
+ def set_tenant_id
41
+ self.tenant_id ||= Vert::Current.tenant_id
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "discard"
4
+
5
+ module Vert
6
+ module Concerns
7
+ module SoftDeletable
8
+ extend ActiveSupport::Concern
9
+
10
+ included do
11
+ include ::Discard::Model
12
+ default_scope -> { kept }
13
+ end
14
+
15
+ class_methods do
16
+ def deleted
17
+ discarded
18
+ end
19
+
20
+ def active
21
+ kept
22
+ end
23
+
24
+ def with_deleted
25
+ with_discarded
26
+ end
27
+
28
+ def only_deleted
29
+ discarded
30
+ end
31
+ end
32
+
33
+ def soft_delete
34
+ discard
35
+ end
36
+
37
+ def restore
38
+ undiscard
39
+ end
40
+
41
+ def deleted?
42
+ discarded?
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Vert
4
+ module Concerns
5
+ module UuidPrimaryKey
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ before_create :set_uuid
10
+ end
11
+
12
+ private
13
+
14
+ def set_uuid
15
+ return unless has_attribute?(:id)
16
+ return if id.present?
17
+ self.id = generate_uuid_v7
18
+ end
19
+
20
+ def generate_uuid_v7
21
+ if SecureRandom.respond_to?(:uuid_v7)
22
+ SecureRandom.uuid_v7
23
+ else
24
+ generate_uuid_v7_fallback
25
+ end
26
+ end
27
+
28
+ def generate_uuid_v7_fallback
29
+ timestamp_ms = (Time.now.to_f * 1000).to_i
30
+ random_bytes = SecureRandom.random_bytes(10)
31
+ bytes = [
32
+ (timestamp_ms >> 40) & 0xFF, (timestamp_ms >> 32) & 0xFF, (timestamp_ms >> 24) & 0xFF,
33
+ (timestamp_ms >> 16) & 0xFF, (timestamp_ms >> 8) & 0xFF, timestamp_ms & 0xFF,
34
+ (0x70 | (random_bytes[0] & 0x0F)), random_bytes[1], (0x80 | (random_bytes[2] & 0x3F)),
35
+ random_bytes[3], random_bytes[4], random_bytes[5], random_bytes[6], random_bytes[7], random_bytes[8], random_bytes[9]
36
+ ].pack("C*")
37
+ hex = bytes.unpack1("H*")
38
+ "#{hex[0..7]}-#{hex[8..11]}-#{hex[12..15]}-#{hex[16..19]}-#{hex[20..31]}"
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Vert
4
+ # Configuração central da gem. Todos os recursos são opcionais e ativados no initializer.
5
+ #
6
+ # @example config/initializers/vert.rb
7
+ # Vert.configure do |config|
8
+ # config.enable_rls = true
9
+ # config.enable_outbox = true
10
+ # config.enable_health = true
11
+ # config.rabbitmq_url = ENV["RABBITMQ_URL"]
12
+ # end
13
+ class Configuration
14
+ # --- Flags de funcionalidade (todos opcionais) ---
15
+ attr_accessor :enable_rls,
16
+ :enable_outbox,
17
+ :enable_health,
18
+ :enable_authorization,
19
+ :enable_multi_tenant,
20
+ :enable_auditable,
21
+ :enable_soft_deletable,
22
+ :enable_uuid_primary_key,
23
+ :enable_company_scoped,
24
+ :enable_document_storeable
25
+
26
+ # --- RLS (Row Level Security) ---
27
+ attr_accessor :rls_user
28
+
29
+ # --- RabbitMQ / Outbox ---
30
+ attr_accessor :rabbitmq_url, :exchange_name
31
+
32
+ # --- Document service client ---
33
+ attr_accessor :document_service_url
34
+
35
+ # --- Health ---
36
+ attr_accessor :health_check_path, :auto_mount_health_routes,
37
+ :health_check_database, :health_check_redis,
38
+ :health_check_rabbitmq, :health_check_sidekiq
39
+
40
+ def initialize
41
+ # Funcionalidades desativadas por padrão; ative no initializer conforme necessário
42
+ @enable_rls = false
43
+ @enable_outbox = false
44
+ @enable_health = true
45
+ @enable_authorization = false
46
+ @enable_multi_tenant = false
47
+ @enable_auditable = false
48
+ @enable_soft_deletable = false
49
+ @enable_uuid_primary_key = false
50
+ @enable_company_scoped = false
51
+ @enable_document_storeable = false
52
+
53
+ @rls_user = ENV.fetch("RLS_USER", "app_user")
54
+ @rabbitmq_url = ENV.fetch("RABBITMQ_URL", "amqp://guest:guest@localhost:5672/")
55
+ @exchange_name = ENV.fetch("RABBITMQ_EXCHANGE", "vert.events")
56
+ @document_service_url = ENV.fetch("DOCUMENT_SERVICE_URL", "http://localhost:3020")
57
+ @health_check_path = "/health"
58
+ @auto_mount_health_routes = false
59
+ @health_check_database = true
60
+ @health_check_redis = false
61
+ @health_check_rabbitmq = false
62
+ @health_check_sidekiq = false
63
+ end
64
+ end
65
+ end