collavre 0.20.2 → 0.21.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 (109) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/stylesheets/collavre/actiontext.css +92 -2
  3. data/app/assets/stylesheets/collavre/code_highlight.css +144 -26
  4. data/app/assets/stylesheets/collavre/comments_popup.css +83 -0
  5. data/app/assets/stylesheets/collavre/landing.css +507 -0
  6. data/app/channels/collavre/comments_presence_channel.rb +7 -0
  7. data/app/controllers/collavre/admin/integrations_controller.rb +82 -0
  8. data/app/controllers/collavre/admin/settings_controller.rb +22 -17
  9. data/app/controllers/collavre/application_controller.rb +27 -0
  10. data/app/controllers/collavre/channels_controller.rb +23 -0
  11. data/app/controllers/collavre/creatives_controller.rb +50 -6
  12. data/app/controllers/collavre/landing_controller.rb +8 -0
  13. data/app/controllers/collavre/passwords_controller.rb +1 -0
  14. data/app/controllers/collavre/public_assets_controller.rb +24 -0
  15. data/app/controllers/collavre/topics_controller.rb +21 -30
  16. data/app/helpers/collavre/comments_helper.rb +7 -0
  17. data/app/helpers/collavre/public_assets_helper.rb +14 -0
  18. data/app/javascript/controllers/comment_controller.js +9 -0
  19. data/app/javascript/controllers/comments/form_controller.js +4 -0
  20. data/app/javascript/controllers/comments/list_controller.js +10 -7
  21. data/app/javascript/controllers/comments/popup_controller.js +9 -0
  22. data/app/javascript/controllers/comments/presence_controller.js +83 -1
  23. data/app/javascript/controllers/comments/topics_controller.js +15 -0
  24. data/app/javascript/controllers/creatives/__tests__/sync_controller.test.js +89 -0
  25. data/app/javascript/controllers/creatives/__tests__/tree_controller.test.js +120 -0
  26. data/app/javascript/controllers/creatives/sync_controller.js +30 -9
  27. data/app/javascript/controllers/creatives/tree_controller.js +23 -0
  28. data/app/javascript/controllers/index.js +4 -1
  29. data/app/javascript/controllers/landing_video_controller.js +53 -0
  30. data/app/javascript/creatives/tree_renderer.js +6 -0
  31. data/app/javascript/lib/api/__tests__/queue_manager.test.js +27 -0
  32. data/app/javascript/lib/api/queue_manager.js +17 -5
  33. data/app/javascript/modules/__tests__/command_args_form.test.js +103 -0
  34. data/app/javascript/modules/__tests__/html_content_empty.test.js +41 -0
  35. data/app/javascript/modules/__tests__/markdown_source_reconcile.test.js +70 -0
  36. data/app/javascript/modules/command_args_form.js +22 -4
  37. data/app/javascript/modules/command_menu.js +27 -0
  38. data/app/javascript/modules/creative_row_editor.js +227 -17
  39. data/app/javascript/modules/html_content_empty.js +12 -0
  40. data/app/javascript/modules/markdown_source_reconcile.js +53 -0
  41. data/app/jobs/collavre/drop_trigger_job.rb +37 -8
  42. data/app/mailers/collavre/application_mailer.rb +1 -1
  43. data/app/models/collavre/channel/injected_message.rb +5 -0
  44. data/app/models/collavre/channel.rb +87 -0
  45. data/app/models/collavre/creative/describable.rb +65 -3
  46. data/app/models/collavre/creative.rb +2 -0
  47. data/app/models/collavre/integration_setting.rb +35 -0
  48. data/app/models/collavre/preview_channel.rb +93 -0
  49. data/app/models/collavre/system_setting.rb +13 -2
  50. data/app/models/collavre/topic.rb +3 -25
  51. data/app/models/concerns/collavre/ai_agent_resolvable.rb +12 -3
  52. data/app/services/collavre/ai_client.rb +3 -3
  53. data/app/services/collavre/channel_attacher.rb +58 -0
  54. data/app/services/collavre/comments/mcp_command.rb +31 -1
  55. data/app/services/collavre/creatives/tree_builder.rb +7 -3
  56. data/app/services/collavre/google_calendar_service.rb +4 -2
  57. data/app/services/collavre/markdown_converter.rb +130 -15
  58. data/app/services/collavre/markdown_importer.rb +7 -2
  59. data/app/services/collavre/orchestration/policy_resolver.rb +11 -1
  60. data/app/services/collavre/tools/creative_attach_files_service.rb +96 -0
  61. data/app/services/collavre/tools/creative_list_attachments_service.rb +42 -0
  62. data/app/services/collavre/tools/creative_remove_attachment_service.rb +35 -0
  63. data/app/services/collavre/tools/permission_denied_error.rb +9 -0
  64. data/app/services/collavre/tools/preview_attach_service.rb +128 -0
  65. data/app/services/collavre/tools/preview_detach_service.rb +61 -0
  66. data/app/services/collavre/tools/topic_authorizer.rb +24 -0
  67. data/app/services/collavre/topic_branch_service.rb +34 -26
  68. data/app/views/admin/shared/_tabs.html.erb +1 -0
  69. data/app/views/collavre/admin/integrations/_category.html.erb +22 -0
  70. data/app/views/collavre/admin/integrations/_setting_row.html.erb +54 -0
  71. data/app/views/collavre/admin/integrations/index.html.erb +42 -0
  72. data/app/views/collavre/admin/settings/_system_tab.html.erb +8 -0
  73. data/app/views/collavre/comments/_channel_chips.html.erb +33 -0
  74. data/app/views/collavre/comments/_comment.html.erb +6 -1
  75. data/app/views/collavre/comments/_comments_popup.html.erb +1 -0
  76. data/app/views/collavre/creatives/_inline_edit_form.html.erb +19 -0
  77. data/app/views/collavre/creatives/index.html.erb +10 -2
  78. data/app/views/collavre/landing/show.html.erb +130 -0
  79. data/app/views/layouts/collavre/landing.html.erb +33 -0
  80. data/config/locales/admin.en.yml +4 -2
  81. data/config/locales/admin.ko.yml +4 -2
  82. data/config/locales/channels.en.yml +11 -0
  83. data/config/locales/channels.ko.yml +11 -0
  84. data/config/locales/comments.en.yml +2 -0
  85. data/config/locales/comments.ko.yml +2 -0
  86. data/config/locales/creatives.en.yml +9 -0
  87. data/config/locales/creatives.ko.yml +8 -0
  88. data/config/locales/integrations.en.yml +44 -0
  89. data/config/locales/integrations.ko.yml +44 -0
  90. data/config/locales/landing.en.yml +51 -0
  91. data/config/locales/landing.ko.yml +51 -0
  92. data/config/routes.rb +18 -0
  93. data/db/migrate/20260526000000_create_channels.rb +42 -0
  94. data/db/migrate/20260527000000_add_dismissed_at_to_channels.rb +6 -0
  95. data/db/migrate/20260527000100_backfill_dismissed_at_for_legacy_detached_channels.rb +28 -0
  96. data/db/migrate/20260528000000_add_preview_channel_unique_index.rb +31 -0
  97. data/db/migrate/20260529000000_add_primary_agent_id_to_topics.rb +40 -0
  98. data/db/migrate/20260529100000_create_integration_settings.rb +15 -0
  99. data/db/seeds.rb +19 -0
  100. data/lib/collavre/aws_credentials.rb +75 -0
  101. data/lib/collavre/engine.rb +51 -0
  102. data/lib/collavre/integration_settings/key_definition.rb +29 -0
  103. data/lib/collavre/integration_settings/registry.rb +55 -0
  104. data/lib/collavre/integration_settings/resolver.rb +71 -0
  105. data/lib/collavre/integration_settings.rb +46 -0
  106. data/lib/collavre/ses_settings_interceptor.rb +72 -0
  107. data/lib/collavre/version.rb +1 -1
  108. data/lib/collavre.rb +3 -0
  109. metadata +52 -1
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "singleton"
4
+
5
+ module Collavre
6
+ module IntegrationSettings
7
+ # Singleton registry of integration setting key definitions.
8
+ # Engines register their keys at boot via `to_prepare`, then the
9
+ # admin UI and {Resolver} consult this registry.
10
+ class Registry
11
+ include Singleton
12
+
13
+ def initialize
14
+ @definitions = {}
15
+ end
16
+
17
+ # Register a key definition.
18
+ #
19
+ # @param key [Symbol, String] canonical identifier (e.g. :slack_client_id)
20
+ # @param category [String] grouping label (e.g. "slack")
21
+ # @param sensitive [Boolean] when true, value is masked in admin UI
22
+ # @param requires_restart [Boolean] when true, surfaces restart-required badge
23
+ # @param env_var [String, nil] ENV variable name (defaults to key.upcase)
24
+ # @param default [String, nil] static fallback used when DB & ENV blank
25
+ # @return [KeyDefinition]
26
+ def register(key, category:, sensitive: true, requires_restart: false, env_var: nil, default: nil)
27
+ key = key.to_sym
28
+ @definitions[key] = KeyDefinition.new(
29
+ key: key,
30
+ category: category,
31
+ sensitive: sensitive,
32
+ requires_restart: requires_restart,
33
+ env_var: env_var || key.to_s.upcase,
34
+ default: default
35
+ )
36
+ end
37
+
38
+ # @return [Array<KeyDefinition>] all registered definitions (frozen snapshot)
39
+ def all
40
+ @definitions.values.freeze
41
+ end
42
+
43
+ # @param key [Symbol, String]
44
+ # @return [KeyDefinition, nil]
45
+ def find(key)
46
+ @definitions[key.to_sym]
47
+ end
48
+
49
+ # @return [Hash{String => Array<KeyDefinition>}] definitions grouped by category
50
+ def by_category
51
+ @definitions.values.group_by(&:category)
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Collavre
4
+ module ::Collavre::IntegrationSettings
5
+ # Resolves the live value for a registered integration setting key.
6
+ #
7
+ # Precedence: **DB > ENV > registered default.**
8
+ # - DB value wins as long as an `::Collavre::IntegrationSetting` row exists with a
9
+ # non-blank value (encrypted at rest via `::Collavre::IntegrationSetting`).
10
+ # - ENV is consulted only when no DB row exists.
11
+ # - The registry's static default is the final fallback.
12
+ #
13
+ # Caching:
14
+ # - **Sensitive** definitions are NEVER cached. `Rails.cache` may resolve
15
+ # to a durable store (e.g. `:solid_cache_store` in production), which
16
+ # would persist decrypted secrets outside the encrypted `value` column
17
+ # and defeat at-rest encryption. Sensitive reads hit the DB every time.
18
+ # - **Non-sensitive** definitions are memoized in `Rails.cache` for 5
19
+ # minutes under `::Collavre::IntegrationSetting.cache_key_for(key)`. The model's
20
+ # `after_commit` hook invalidates this key on any write.
21
+ class Resolver
22
+ # Raised by {.get} when the key has not been registered.
23
+ class UnknownKeyError < StandardError; end
24
+
25
+ CACHE_TTL = 5.minutes
26
+
27
+ class << self
28
+ # Resolve the current value for a registered key.
29
+ #
30
+ # @param key [Symbol, String]
31
+ # @return [String, nil]
32
+ # @raise [UnknownKeyError] if the key is not registered
33
+ def get(key)
34
+ definition = Registry.instance.find(key) or
35
+ raise UnknownKeyError, "Unknown integration setting: #{key}"
36
+
37
+ return resolve(definition) if definition.sensitive
38
+
39
+ Rails.cache.fetch(::Collavre::IntegrationSetting.cache_key_for(definition.key), expires_in: CACHE_TTL) do
40
+ resolve(definition)
41
+ end
42
+ end
43
+
44
+ # Report which source currently provides the value for a key.
45
+ #
46
+ # @param key [Symbol, String]
47
+ # @return [Symbol] one of `:db`, `:env`, `:default`, or `:unknown`
48
+ def source_for(key)
49
+ definition = Registry.instance.find(key) or return :unknown
50
+ return :db if ::Collavre::IntegrationSetting.find_by(key: definition.key)&.value.present?
51
+ return :env if ENV[definition.env_var].present?
52
+ :default
53
+ end
54
+
55
+ private
56
+
57
+ def resolve(definition)
58
+ db_value(definition) || env_value(definition) || definition.default
59
+ end
60
+
61
+ def db_value(definition)
62
+ ::Collavre::IntegrationSetting.find_by(key: definition.key)&.value.presence
63
+ end
64
+
65
+ def env_value(definition)
66
+ ENV[definition.env_var].presence
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Entry point for the Collavre integration settings subsystem.
4
+ # Loads the registry value-object, registry singleton, and resolver
5
+ # (when present). Loaded from `engines/collavre/lib/collavre.rb` so
6
+ # constants are available before any engine `to_prepare` blocks run.
7
+
8
+ require_relative "integration_settings/key_definition"
9
+ require_relative "integration_settings/registry"
10
+ require_relative "integration_settings/resolver"
11
+
12
+ module Collavre
13
+ module IntegrationSettings
14
+ # Resolve a registered key with a safety net for boot-time consumers.
15
+ # Returns `Resolver.get(key)` when the registry+DB are reachable, otherwise
16
+ # falls back to `ENV[key.upcase]`. After the next boot, the DB value wins —
17
+ # matching the `requires_restart` semantics callers register.
18
+ #
19
+ # `boot_safe: true` additionally rescues `ActiveRecord::Encryption::Errors::Base`
20
+ # so callers reached before `config/initializers/active_record_encryption.rb`
21
+ # runs (e.g. `storage.yml`, `config/environments/*.rb`) cannot crash the boot
22
+ # if an encrypted row is unreadable. Runtime callers MUST leave this false so
23
+ # decryption failures surface instead of silently treating values as blank.
24
+ def self.fetch(key, default: nil, boot_safe: false)
25
+ return ENV[key.to_s.upcase].presence || default unless defined?(Resolver)
26
+
27
+ value =
28
+ begin
29
+ Resolver.get(key)
30
+ rescue Resolver::UnknownKeyError
31
+ nil
32
+ rescue ActiveRecord::StatementInvalid,
33
+ ActiveRecord::NoDatabaseError,
34
+ ActiveRecord::ConnectionNotEstablished,
35
+ NameError
36
+ ENV[key.to_s.upcase]
37
+ rescue StandardError => e
38
+ raise unless boot_safe &&
39
+ defined?(ActiveRecord::Encryption::Errors::Base) &&
40
+ e.is_a?(ActiveRecord::Encryption::Errors::Base)
41
+ ENV[key.to_s.upcase]
42
+ end
43
+ value.presence || default
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Collavre
4
+ # ActionMailer interceptor that injects AWS SES SMTP settings (address,
5
+ # user_name, password) into each outgoing message at send time, sourced
6
+ # from `IntegrationSettings` (DB > ENV) with a Rails credentials fallback.
7
+ #
8
+ # Registered via `Collavre::Engine` so admins can rotate SES credentials
9
+ # through `/admin/integrations` without redeploying. Only acts on SMTP
10
+ # delivery — other delivery methods (`:test`, `:letter_opener`, etc.) pass
11
+ # through untouched.
12
+ class SesSettingsInterceptor
13
+ SES_ADDRESS_PATTERN = /\Aemail-smtp\.[a-z0-9-]+\.amazonaws\.com\z/
14
+
15
+ class << self
16
+ def delivering_email(message)
17
+ return unless message.delivery_method.is_a?(::Mail::SMTP)
18
+
19
+ settings = message.delivery_method.settings
20
+ # Scope to SES-bound messages only. The engine registers this
21
+ # interceptor globally, so host apps using a non-SES SMTP provider
22
+ # (SendGrid, Mailgun, custom relay) must pass through untouched —
23
+ # otherwise we'd clobber their address/user_name/password.
24
+ return unless ses_target?(settings)
25
+
26
+ region = resolve_region
27
+ creds = Collavre::AwsCredentials.ses_smtp
28
+
29
+ settings[:address] = "email-smtp.#{region}.amazonaws.com" if region.present?
30
+ # `AwsCredentials.ses_smtp` returns only source-coherent pairs (both DB,
31
+ # both ENV, or both credentials). When admins save just one half via
32
+ # /admin/integrations while the other still lives in ENV, the helper
33
+ # drops the partial DB write and falls through to a coherent ENV/cred
34
+ # pair, avoiding mismatched (db-user, env-pass) injections that would
35
+ # break every SMTP delivery.
36
+ if creds[:user_name].present? && creds[:password].present?
37
+ settings[:user_name] = creds[:user_name]
38
+ settings[:password] = creds[:password]
39
+ else
40
+ # No coherent pair available (admin reset DB and no ENV/credentials
41
+ # fallback). Clear stale settings so we don't keep using boot-time
42
+ # or previously-injected credentials — these keys are registered
43
+ # with requires_restart: false, so runtime reset must take effect.
44
+ settings.delete(:user_name)
45
+ settings.delete(:password)
46
+ end
47
+ end
48
+
49
+ private
50
+
51
+ # SES intent is signaled exclusively by an SES-shaped SMTP address
52
+ # (`email-smtp.<region>.amazonaws.com`). The boot scaffold in
53
+ # `config/environments/production.rb` only emits that shape when
54
+ # `ses_region` is resolvable, so a non-SES address — including
55
+ # `Mail::SMTP`'s hard-coded `"localhost"` default and explicit relays
56
+ # like `smtp.sendgrid.net` — means the host is using a different
57
+ # provider (or a real local relay). Bail in those cases so we don't
58
+ # clobber the host's address or wipe authenticated credentials.
59
+ def ses_target?(settings)
60
+ address = settings[:address].to_s
61
+ return true if address.empty?
62
+
63
+ address.match?(SES_ADDRESS_PATTERN)
64
+ end
65
+
66
+ def resolve_region
67
+ value = Collavre::IntegrationSettings.fetch(:aws_region, default: ENV["AWS_REGION"])
68
+ value.presence || Rails.application.credentials.dig(:aws, :region)
69
+ end
70
+ end
71
+ end
72
+ end
@@ -1,3 +1,3 @@
1
1
  module Collavre
2
- VERSION = "0.20.2"
2
+ VERSION = "0.21.0"
3
3
  end
data/lib/collavre.rb CHANGED
@@ -3,6 +3,9 @@ require "collavre/configuration"
3
3
  require "collavre/engine"
4
4
  require "collavre/user_extensions"
5
5
  require "collavre/integration_registry"
6
+ require "collavre/integration_settings"
7
+ require "collavre/aws_credentials"
8
+ require "collavre/ses_settings_interceptor"
6
9
  require "collavre/view_extensions"
7
10
  require "navigation/registry"
8
11
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: collavre
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.20.2
4
+ version: 0.21.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Collavre
@@ -184,6 +184,7 @@ files:
184
184
  - app/assets/stylesheets/collavre/design_tokens.css
185
185
  - app/assets/stylesheets/collavre/gnb.css
186
186
  - app/assets/stylesheets/collavre/image_lightbox.css
187
+ - app/assets/stylesheets/collavre/landing.css
187
188
  - app/assets/stylesheets/collavre/mention_menu.css
188
189
  - app/assets/stylesheets/collavre/modal_dialog.css
189
190
  - app/assets/stylesheets/collavre/org_chart.css
@@ -209,11 +210,13 @@ files:
209
210
  - app/components/collavre/progress_filter_component.html.erb
210
211
  - app/components/collavre/progress_filter_component.rb
211
212
  - app/components/collavre/user_mention_menu_component.rb
213
+ - app/controllers/collavre/admin/integrations_controller.rb
212
214
  - app/controllers/collavre/admin/orchestration_controller.rb
213
215
  - app/controllers/collavre/admin/settings_controller.rb
214
216
  - app/controllers/collavre/application_controller.rb
215
217
  - app/controllers/collavre/attachments_controller.rb
216
218
  - app/controllers/collavre/calendar_events_controller.rb
219
+ - app/controllers/collavre/channels_controller.rb
217
220
  - app/controllers/collavre/comment_read_pointers_controller.rb
218
221
  - app/controllers/collavre/comments/activity_logs_controller.rb
219
222
  - app/controllers/collavre/comments/reactions_controller.rb
@@ -235,7 +238,9 @@ files:
235
238
  - app/controllers/collavre/google_auth_controller.rb
236
239
  - app/controllers/collavre/inbox_items_controller.rb
237
240
  - app/controllers/collavre/invites_controller.rb
241
+ - app/controllers/collavre/landing_controller.rb
238
242
  - app/controllers/collavre/passwords_controller.rb
243
+ - app/controllers/collavre/public_assets_controller.rb
239
244
  - app/controllers/collavre/sessions_controller.rb
240
245
  - app/controllers/collavre/tasks_controller.rb
241
246
  - app/controllers/collavre/topics_controller.rb
@@ -260,6 +265,7 @@ files:
260
265
  - app/helpers/collavre/comments_helper.rb
261
266
  - app/helpers/collavre/creatives_helper.rb
262
267
  - app/helpers/collavre/navigation_helper.rb
268
+ - app/helpers/collavre/public_assets_helper.rb
263
269
  - app/javascript/collavre.js
264
270
  - app/javascript/components/ImageResizer.jsx
265
271
  - app/javascript/components/InlineLexicalEditor.jsx
@@ -290,6 +296,8 @@ files:
290
296
  - app/javascript/controllers/comments/review_quotes_store.js
291
297
  - app/javascript/controllers/comments/topics_controller.js
292
298
  - app/javascript/controllers/common_popup_controller.js
299
+ - app/javascript/controllers/creatives/__tests__/sync_controller.test.js
300
+ - app/javascript/controllers/creatives/__tests__/tree_controller.test.js
293
301
  - app/javascript/controllers/creatives/drag_drop_controller.js
294
302
  - app/javascript/controllers/creatives/expansion_controller.js
295
303
  - app/javascript/controllers/creatives/import_controller.js
@@ -299,6 +307,7 @@ files:
299
307
  - app/javascript/controllers/creatives/tree_controller.js
300
308
  - app/javascript/controllers/image_lightbox_controller.js
301
309
  - app/javascript/controllers/index.js
310
+ - app/javascript/controllers/landing_video_controller.js
302
311
  - app/javascript/controllers/link_creative_controller.js
303
312
  - app/javascript/controllers/org_chart_controller.js
304
313
  - app/javascript/controllers/popup_menu_controller.js
@@ -339,7 +348,10 @@ files:
339
348
  - app/javascript/lib/turbo_stream_actions.js
340
349
  - app/javascript/lib/utils/markdown.js
341
350
  - app/javascript/lib/utils/table_download.js
351
+ - app/javascript/modules/__tests__/command_args_form.test.js
342
352
  - app/javascript/modules/__tests__/creative_progress.test.js
353
+ - app/javascript/modules/__tests__/html_content_empty.test.js
354
+ - app/javascript/modules/__tests__/markdown_source_reconcile.test.js
343
355
  - app/javascript/modules/command_args_form.js
344
356
  - app/javascript/modules/command_menu.js
345
357
  - app/javascript/modules/creative_guide.js
@@ -348,9 +360,11 @@ files:
348
360
  - app/javascript/modules/creative_row_swipe.js
349
361
  - app/javascript/modules/creatives.js
350
362
  - app/javascript/modules/export_to_markdown.js
363
+ - app/javascript/modules/html_content_empty.js
351
364
  - app/javascript/modules/inbox_panel.js
352
365
  - app/javascript/modules/integration_wizard.js
353
366
  - app/javascript/modules/lexical_inline_editor.jsx
367
+ - app/javascript/modules/markdown_source_reconcile.js
354
368
  - app/javascript/modules/mention_menu.js
355
369
  - app/javascript/modules/modal_dialog.js
356
370
  - app/javascript/modules/slide_view.js
@@ -385,6 +399,8 @@ files:
385
399
  - app/models/collavre/activity_log.rb
386
400
  - app/models/collavre/application_record.rb
387
401
  - app/models/collavre/calendar_event.rb
402
+ - app/models/collavre/channel.rb
403
+ - app/models/collavre/channel/injected_message.rb
388
404
  - app/models/collavre/comment.rb
389
405
  - app/models/collavre/comment/approvable.rb
390
406
  - app/models/collavre/comment/broadcastable.rb
@@ -407,10 +423,12 @@ files:
407
423
  - app/models/collavre/device.rb
408
424
  - app/models/collavre/email.rb
409
425
  - app/models/collavre/inbox_item.rb
426
+ - app/models/collavre/integration_setting.rb
410
427
  - app/models/collavre/invitation.rb
411
428
  - app/models/collavre/label.rb
412
429
  - app/models/collavre/mcp_tool.rb
413
430
  - app/models/collavre/orchestrator_policy.rb
431
+ - app/models/collavre/preview_channel.rb
414
432
  - app/models/collavre/session.rb
415
433
  - app/models/collavre/system_setting.rb
416
434
  - app/models/collavre/tag.rb
@@ -435,6 +453,7 @@ files:
435
453
  - app/services/collavre/ai_client.rb
436
454
  - app/services/collavre/ai_system_prompt_renderer.rb
437
455
  - app/services/collavre/auto_theme_generator.rb
456
+ - app/services/collavre/channel_attacher.rb
438
457
  - app/services/collavre/command_menu_service.rb
439
458
  - app/services/collavre/comment_link_formatter.rb
440
459
  - app/services/collavre/comment_move_service.rb
@@ -490,9 +509,12 @@ files:
490
509
  - app/services/collavre/ruby_llm_interaction_logger.rb
491
510
  - app/services/collavre/system_events/context_builder.rb
492
511
  - app/services/collavre/system_events/dispatcher.rb
512
+ - app/services/collavre/tools/creative_attach_files_service.rb
493
513
  - app/services/collavre/tools/creative_batch_service.rb
494
514
  - app/services/collavre/tools/creative_create_service.rb
495
515
  - app/services/collavre/tools/creative_import_service.rb
516
+ - app/services/collavre/tools/creative_list_attachments_service.rb
517
+ - app/services/collavre/tools/creative_remove_attachment_service.rb
496
518
  - app/services/collavre/tools/creative_retrieval_service.rb
497
519
  - app/services/collavre/tools/creative_update_service.rb
498
520
  - app/services/collavre/tools/cron_cancel_service.rb
@@ -500,14 +522,22 @@ files:
500
522
  - app/services/collavre/tools/cron_list_service.rb
501
523
  - app/services/collavre/tools/cron_update_service.rb
502
524
  - app/services/collavre/tools/description_normalizable.rb
525
+ - app/services/collavre/tools/permission_denied_error.rb
526
+ - app/services/collavre/tools/preview_attach_service.rb
527
+ - app/services/collavre/tools/preview_detach_service.rb
528
+ - app/services/collavre/tools/topic_authorizer.rb
503
529
  - app/services/collavre/topic_branch_service.rb
504
530
  - app/views/admin/shared/_tabs.html.erb
531
+ - app/views/collavre/admin/integrations/_category.html.erb
532
+ - app/views/collavre/admin/integrations/_setting_row.html.erb
533
+ - app/views/collavre/admin/integrations/index.html.erb
505
534
  - app/views/collavre/admin/orchestration/show.html.erb
506
535
  - app/views/collavre/admin/settings/_system_tab.html.erb
507
536
  - app/views/collavre/admin/settings/_uiux_tab.html.erb
508
537
  - app/views/collavre/admin/settings/index.html.erb
509
538
  - app/views/collavre/admin/settings/uiux.html.erb
510
539
  - app/views/collavre/comments/_activity_log_details.html.erb
540
+ - app/views/collavre/comments/_channel_chips.html.erb
511
541
  - app/views/collavre/comments/_comment.html.erb
512
542
  - app/views/collavre/comments/_comments_popup.html.erb
513
543
  - app/views/collavre/comments/_list.html.erb
@@ -538,6 +568,7 @@ files:
538
568
  - app/views/collavre/invitation_mailer/invite.html.erb
539
569
  - app/views/collavre/invitation_mailer/invite.text.erb
540
570
  - app/views/collavre/invites/show.html.erb
571
+ - app/views/collavre/landing/show.html.erb
541
572
  - app/views/collavre/passwords/edit.html.erb
542
573
  - app/views/collavre/passwords/new.html.erb
543
574
  - app/views/collavre/passwords_mailer/reset.html.erb
@@ -568,11 +599,14 @@ files:
568
599
  - app/views/collavre/users/passkeys.html.erb
569
600
  - app/views/collavre/users/show.html.erb
570
601
  - app/views/inbox/badge_component/_count.html.erb
602
+ - app/views/layouts/collavre/landing.html.erb
571
603
  - app/views/layouts/collavre/slide.html.erb
572
604
  - config/locales/admin.en.yml
573
605
  - config/locales/admin.ko.yml
574
606
  - config/locales/ai_agent.en.yml
575
607
  - config/locales/ai_agent.ko.yml
608
+ - config/locales/channels.en.yml
609
+ - config/locales/channels.ko.yml
576
610
  - config/locales/comments.en.yml
577
611
  - config/locales/comments.ko.yml
578
612
  - config/locales/contacts.en.yml
@@ -583,8 +617,12 @@ files:
583
617
  - config/locales/creatives.ko.yml
584
618
  - config/locales/drop_trigger.en.yml
585
619
  - config/locales/drop_trigger.ko.yml
620
+ - config/locales/integrations.en.yml
621
+ - config/locales/integrations.ko.yml
586
622
  - config/locales/invites.en.yml
587
623
  - config/locales/invites.ko.yml
624
+ - config/locales/landing.en.yml
625
+ - config/locales/landing.ko.yml
588
626
  - config/locales/notifications.en.yml
589
627
  - config/locales/notifications.ko.yml
590
628
  - config/locales/orchestration.en.yml
@@ -709,10 +747,23 @@ files:
709
747
  - db/migrate/20260409000000_add_source_topic_id_to_topics.rb
710
748
  - db/migrate/20260415000000_create_main_topics_for_existing_creatives.rb
711
749
  - db/migrate/20260415094811_add_task_id_to_comments.rb
750
+ - db/migrate/20260526000000_create_channels.rb
751
+ - db/migrate/20260527000000_add_dismissed_at_to_channels.rb
752
+ - db/migrate/20260527000100_backfill_dismissed_at_for_legacy_detached_channels.rb
753
+ - db/migrate/20260528000000_add_preview_channel_unique_index.rb
754
+ - db/migrate/20260529000000_add_primary_agent_id_to_topics.rb
755
+ - db/migrate/20260529100000_create_integration_settings.rb
756
+ - db/seeds.rb
712
757
  - lib/collavre.rb
758
+ - lib/collavre/aws_credentials.rb
713
759
  - lib/collavre/configuration.rb
714
760
  - lib/collavre/engine.rb
715
761
  - lib/collavre/integration_registry.rb
762
+ - lib/collavre/integration_settings.rb
763
+ - lib/collavre/integration_settings/key_definition.rb
764
+ - lib/collavre/integration_settings/registry.rb
765
+ - lib/collavre/integration_settings/resolver.rb
766
+ - lib/collavre/ses_settings_interceptor.rb
716
767
  - lib/collavre/user_extensions.rb
717
768
  - lib/collavre/version.rb
718
769
  - lib/collavre/view_extensions.rb