Class: CommandTower::Messaging::Rendering::InboxDocumentRenderer

Inherits:
Object
  • Object
show all
Defined in:
app/services/command_tower/messaging/rendering/inbox_document_renderer.rb

Overview

Internal Messaging::Rendering collaborator (peer of ChannelRenderer, not a host-facing service). Builds the InboxDocument shown at Inbox detail read time.

Generic path: one paragraph block from communication.body, plus an optional cta block with a typed destination — internal (metadata["deep_link_path"], origin-free, host-navigation-owned) if present and safe, else external (metadata["deep_link"]) if that is a safe href (D-INBOX-GENERIC; typed destination added Slice 2.6.4).

Optional per-notification_type_key override: a pure-Ruby composer class (declaration.inbox_document_composer, resolved via NotificationTypes.lookup + .constantize), .call(communication:) -> InboxDocument. Any failure (unregistered type, absent composer, unresolvable class name, a raising composer, or a composer returning something other than an InboxDocument) fails open to the generic document — the Inbox read path must never 500 on a bad type composer (D-INBOX-TYPE). This replaces the Rich Messaging Campaign 2 ERB/JSON authoring path entirely — see artifacts/visual-improvements/rich-messaging/authority/RICH_MESSAGING_RUBY_INBOX_DEFINITION_DISCOVERY.md.

After the document (type-specific or generic) is built, any "presentation" block is resolved against CommandTower.config.registry.inbox_presentations — at most one attempted/resolved presentation capability per document (Rich Messaging Slice 2.5). The budget is consumed the instant a "presentation"-typed block is seen, before lookup or composition, regardless of outcome, so a malformed/unregistered first node cannot fail open and then let a second node still execute composer domain I/O.

The composer's raw result is always projected down to the registration's declared output_keys before it reaches content.blocks[].data (corrective slice — presentation ServiceResult/context leak fix). Composer inputs and any other incidental context/result keys never reach the wire, regardless of whether the composer is ApplicationService-shaped or a plain Hash.

Constant Summary collapse

UNSAFE_SCHEMES =
%w[javascript data vbscript].freeze
DEFAULT_CTA_LABEL =
"Open"

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(communication:, recipient_id:) ⇒ InboxDocumentRenderer

Returns a new instance of InboxDocumentRenderer.



53
54
55
56
57
# File 'app/services/command_tower/messaging/rendering/inbox_document_renderer.rb', line 53

def initialize(communication:, recipient_id:)
  @communication = communication
  @recipient_id = recipient_id
  @presentation_attempted = false
end

Class Method Details

.render(communication:, recipient_id:) ⇒ Object



49
50
51
# File 'app/services/command_tower/messaging/rendering/inbox_document_renderer.rb', line 49

def self.render(communication:, recipient_id:)
  new(communication:, recipient_id:).render
end

Instance Method Details

#render ⇒ Object



59
60
61
62
63
# File 'app/services/command_tower/messaging/rendering/inbox_document_renderer.rb', line 59

def render
  document = build_from_type_composer || build_generic

  resolve_presentation_blocks(document)
end