infrastructure tier

infrastructure-communication

Multi-channel notifications (Email, SMS, Push, In-App)

Multi-channel notifications (Email, SMS, Push, In-App)

Tierinfrastructure
Roleunclassified (baselined)
Pathcrates/infrastructure/communication
Edition2021
Targetsinfrastructure_communication, integration_tests
Public items18 across 1 module
Tests99

What it is for

Multi-channel notifications and conversations.

Provides:

Capabilities

verb:add

Repository functions for communication models.

Item
async fn add_participant(pool : & PgPool, participant : & ConversationParticipant,) -> Result <ConversationParticipant, CommunicationError>

verb:assign

Repository functions for communication models.

Item
async fn assign_conversation(pool : & PgPool, id : Uuid, assigned_to : Uuid,) -> Result <(), CommunicationError>
async fn assign_conversation_tx(conn : & mut PgConnection, id : Uuid, assigned_to : Uuid,) -> Result <(), CommunicationError>

verb:close

Repository functions for communication models.

Item
async fn close_conversation(pool : & PgPool, id : Uuid, closed_by : Option <Uuid>,) -> Result <(), CommunicationError>

verb:create

Repository functions for communication models.

Item
async fn create_conversation(pool : & PgPool, conversation : & Conversation,) -> Result <Conversation, CommunicationError>
async fn create_message(pool : & PgPool, message : & ChatMessage,) -> Result <ChatMessage, CommunicationError>
async fn create_message_tx(conn : & mut PgConnection, message : & ChatMessage,) -> Result <ChatMessage, CommunicationError>

verb:find

Repository functions for communication models.

Item
async fn find_conversation_by_id(pool : & PgPool, id : Uuid,) -> Result <Option <Conversation>, CommunicationError>
async fn find_conversations_needing_reply(pool : & PgPool,) -> Result <Vec <Conversation>, CommunicationError>
async fn find_participants_by_conversation(pool : & PgPool, conversation_id : Uuid,) -> Result <Vec <ConversationParticipant>, CommunicationError>
async fn find_conversations_for_party(pool : & PgPool, party_id : PartyId,) -> Result <Vec <Conversation>, CommunicationError>
async fn find_messages_by_conversation(pool : & PgPool, conversation_id : Uuid,) -> Result <Vec <ChatMessage>, CommunicationError>

verb:list

Repository functions for communication models.

Item
async fn list_active_conversations(pool : & PgPool,) -> Result <Vec <Conversation>, CommunicationError>

verb:mark

Repository functions for communication models.

Item
async fn mark_participant_read(pool : & PgPool, conversation_id : Uuid, party_id : PartyId,) -> Result <(), CommunicationError>

verb:remove

Repository functions for communication models.

Item
async fn remove_participant(pool : & PgPool, conversation_id : Uuid, party_id : PartyId,) -> Result <(), CommunicationError>

verb:set

Repository functions for communication models.

Item
async fn set_message_status_tx(conn : & mut PgConnection, message_id : Uuid, status : MessageStatus, error : Option <& str>,) -> Result <(), CommunicationError>
async fn set_message_status(pool : & PgPool, message_id : Uuid, status : MessageStatus, error : Option <& str>,) -> Result <(), CommunicationError>

verb:soft

Repository functions for communication models.

Item
async fn soft_delete_conversation(pool : & PgPool, id : Uuid) -> Result <(), CommunicationError>

How to use it

No examples/ target and no doctest in this crate's rustdoc. The tests listed under Verification are the closest executable usage.

Module structure

infrastructure_communication

Public surface

`repo`

ItemWhat it is
async fn create_conversation(pool : & PgPool, conversation : & Conversation,) -> Result <Conversation, CommunicationError>Create a new conversation
async fn find_conversation_by_id(pool : & PgPool, id : Uuid,) -> Result <Option <Conversation>, CommunicationError>Find a conversation by ID
async fn list_active_conversations(pool : & PgPool,) -> Result <Vec <Conversation>, CommunicationError>List active conversations (not closed or deleted)
async fn find_conversations_needing_reply(pool : & PgPool,) -> Result <Vec <Conversation>, CommunicationError>Find conversations needing a reply (last message was inbound)
async fn close_conversation(pool : & PgPool, id : Uuid, closed_by : Option <Uuid>,) -> Result <(), CommunicationError>Close a conversation
async fn assign_conversation(pool : & PgPool, id : Uuid, assigned_to : Uuid,) -> Result <(), CommunicationError>Assign a conversation to a staff user, leaving it active
async fn assign_conversation_tx(conn : & mut PgConnection, id : Uuid, assigned_to : Uuid,) -> Result <(), CommunicationError>Assign a conversation on a caller-supplied connection
async fn soft_delete_conversation(pool : & PgPool, id : Uuid) -> Result <(), CommunicationError>Soft delete a conversation
async fn add_participant(pool : & PgPool, participant : & ConversationParticipant,) -> Result <ConversationParticipant, CommunicationError>Add a participant to a conversation
async fn find_participants_by_conversation(pool : & PgPool, conversation_id : Uuid,) -> Result <Vec <ConversationParticipant>, CommunicationError>Find all participants in a conversation
async fn find_conversations_for_party(pool : & PgPool, party_id : PartyId,) -> Result <Vec <Conversation>, CommunicationError>Find all conversations a party is participating in
async fn mark_participant_read(pool : & PgPool, conversation_id : Uuid, party_id : PartyId,) -> Result <(), CommunicationError>Mark a participant as having read the conversation
async fn remove_participant(pool : & PgPool, conversation_id : Uuid, party_id : PartyId,) -> Result <(), CommunicationError>Remove a participant from a conversation
async fn create_message(pool : & PgPool, message : & ChatMessage,) -> Result <ChatMessage, CommunicationError>Create a new chat message, on its own transaction
async fn create_message_tx(conn : & mut PgConnection, message : & ChatMessage,) -> Result <ChatMessage, CommunicationError>Create a new chat message on a caller-supplied connection
async fn find_messages_by_conversation(pool : & PgPool, conversation_id : Uuid,) -> Result <Vec <ChatMessage>, CommunicationError>Find messages in a conversation
async fn set_message_status_tx(conn : & mut PgConnection, message_id : Uuid, status : MessageStatus, error : Option <& str>,) -> Result <(), CommunicationError>Record a message's delivery outcome
async fn set_message_status(pool : & PgPool, message_id : Uuid, status : MessageStatus, error : Option <& str>,) -> Result <(), CommunicationError>Record a message's delivery outcome, on its own transaction

Re-exports. Exported here, defined elsewhere.

ExportDefined in
CommunicationErrorerror::CommunicationError
SmtpConfigsmtp::SmtpConfig
{AlwaysFailOutboundSender,OutboundError,OutboundOutcome,OutboundSender,StubOutboundSender,}outbound::{AlwaysFailOutboundSender,OutboundError,OutboundOutcome,OutboundSender,StubOutboundSender,}
{Channel,EmailChannel,InAppChannel,PushChannel,SmsChannel}channel::{Channel,EmailChannel,InAppChannel,PushChannel,SmsChannel}
{ChatMessage,MessageChannel,MessageDirection,MessageStatus}chat_message::{ChatMessage,MessageChannel,MessageDirection,MessageStatus}
{Conversation,ConversationParticipant,ConversationStatus,ConversationType,}conversation::{Conversation,ConversationParticipant,ConversationStatus,ConversationType,}
{DiscordConfig,DiscordOutboundSender,DiscordProviderBuilder}discord::{DiscordConfig,DiscordOutboundSender,DiscordProviderBuilder}
{EmailMessage,InAppMessage,Message,PushMessage,SmsMessage}message::{EmailMessage,InAppMessage,Message,PushMessage,SmsMessage}
{EnqueueRequest,InMemorySendService,PgSendService,SendChannel,SendJob,SendJobError,SendJobStatus,SendService,}send_jobs::{EnqueueRequest,InMemorySendService,PgSendService,SendChannel,SendJob,SendJobError,SendJobStatus,SendService,}
{FlowrouteConfig,FlowrouteOutboundSender,FlowrouteProviderBuilder}flowroute::{FlowrouteConfig,FlowrouteOutboundSender,FlowrouteProviderBuilder}
{InMemoryRateLimiter,RateLimitDecision,RateLimiter}rate_limit::{InMemoryRateLimiter,RateLimitDecision,RateLimiter}
{Notification,NotificationStatus}notification::{Notification,NotificationStatus}
{NtfyConfig,NtfyOutboundSender,NtfyProviderBuilder}ntfy::{NtfyConfig,NtfyOutboundSender,NtfyProviderBuilder}
{OutboundBuildError,OutboundProviderRegistry,ProviderBuilder,SmtpProviderBuilder,}provider_registry::{OutboundBuildError,OutboundProviderRegistry,ProviderBuilder,SmtpProviderBuilder,}
{SignalConfig,SignalOutboundSender,SignalProviderBuilder}signal::{SignalConfig,SignalOutboundSender,SignalProviderBuilder}
{SlackConfig,SlackOutboundSender,SlackProviderBuilder}slack::{SlackConfig,SlackOutboundSender,SlackProviderBuilder}
{SmtpOutboundSender,SmtpSenderInitError}smtp::{SmtpOutboundSender,SmtpSenderInitError}
{TeamsConfig,TeamsOutboundSender,TeamsProviderBuilder}teams::{TeamsConfig,TeamsOutboundSender,TeamsProviderBuilder}
{TelegramConfig,TelegramOutboundSender,TelegramProviderBuilder}telegram::{TelegramConfig,TelegramOutboundSender,TelegramProviderBuilder}
{TwilioConfig,TwilioOutboundSender,TwilioProviderBuilder}twilio::{TwilioConfig,TwilioOutboundSender,TwilioProviderBuilder}
{WhatsappConfig,WhatsappOutboundSender,WhatsappProviderBuilder}whatsapp::{WhatsappConfig,WhatsappOutboundSender,WhatsappProviderBuilder}
{delete_system_config,delete_tenant_config,get_system_config,get_tenant_config,list_system_providers,list_tenant_providers,resolve_config,store_system_config,store_tenant_config,touch_tenant_config,ConfigScope,MessagingCredentialsError,MessagingProviderInfo,ResolvedConfig,}messaging_credentials::{delete_system_config,delete_tenant_config,get_system_config,get_tenant_config,list_system_providers,list_tenant_providers,resolve_config,store_system_config,store_tenant_config,touch_tenant_config,ConfigScope,MessagingCredentialsError,MessagingProviderInfo,ResolvedConfig,}
{run_outbound_worker,run_outbound_worker_with_registry,OutboundWorkerConfig,}outbound_worker::{run_outbound_worker,run_outbound_worker_with_registry,OutboundWorkerConfig,}

Boundary

Reaches into foundation, identity.

Shares tier infrastructure with 82 other crates: infrastructure-acquire, infrastructure-adapters-google-calendar, infrastructure-adapters-google-gmail, infrastructure-adapters-google-places, infrastructure-adapters-google-trends, infrastructure-adapters-shodan, infrastructure-adapters-yelp, infrastructure-agent, … (82 total).

_What this crate deliberately does NOT own is a judgment. No committed registry records one for it, so none is stated here._

Where it sits

Tier (ontology)infrastructure
Architectural role (taxonomy)unclassified (baselined)
Locationcrates/infrastructure/communication
Vocabulary in force (lexicon)current

Tier flow. Which tiers this crate's own edges cross.

flowchart LR
  n_infrastructure["infrastructure"] --> n_foundation["foundation"]
  n_infrastructure["infrastructure"] --> n_identity["identity"]

Dependencies

Runtime, in this workspace.

CrateTierOptionalOnly on
`foundation-basemodels`foundationnoalways
`foundation-smtp-transport`foundationnoalways
`identity-parties`identitynoalways
`infrastructure-fetcher`infrastructureyesalways

Runtime, from outside the workspace.

CrateRequirementFeaturesOptionalOnly on
async-trait^0.1noalways
aws-config^1yesalways
aws-sdk-ses^1yesalways
chrono^0.4serdenoalways
lettre^0.11tokio1-native-tlsnoalways
reqwest^0.12json, rustls-tlsyesalways
serde^1derivenoalways
serde_json^1noalways
sqlx^0.8runtime-tokio, postgres, chrono, uuid, jsonnoalways
thiserror^2noalways
tokio^1fullnoalways
tokio-util^0.7rtnoalways
tracing^0.1noalways
uuid^1v4, v7, serde, jsnoalways

Development, from outside the workspace.

CrateRequirementFeaturesOptionalOnly on
dotenvy^0.15noalways
tokio^1fullnoalways
tokio-test^0.4noalways

Build. None.

Depended on by. 3 workspace crates.

Signal flow — what reaches this crate, and what it reaches.

flowchart LR
  n_application_communication["application-communication"] -->|uses| SELF
  n_application_conversation["application-conversation"] -->|uses| SELF
  n_application_messaging["application-messaging"] -->|uses| SELF
  SELF["infrastructure-communication"]
  SELF -->|runtime| n_foundation_basemodels["foundation-basemodels"]
  SELF -->|runtime| n_foundation_smtp_transport["foundation-smtp-transport"]
  SELF -->|runtime| n_identity_parties["identity-parties"]
  SELF -->|runtime| n_infrastructure_fetcher["infrastructure-fetcher"]
  classDef self fill:#1f883d,stroke:#1f883d,color:#fff;
  class SELF self;

Feature flags

FeatureEnablesOn by default
aws-configdep:aws-configno
aws-sdk-sesdep:aws-sdk-sesno
defaulthttp, twilio, whatsapp, flowroute, slack, telegram, discord, teams, … (10 total)yes
discordhttpyes
flowroutehttpyes
httpreqwest, dep:infrastructure-fetcheryes
ntfyhttpyes
postgresno
reqwestdep:reqwestno
sesaws-sdk-ses, aws-configno
signalhttpyes
slackhttpyes
teamshttpyes
telegramhttpyes
twiliohttpyes
whatsapphttpyes
flowchart LR
  n_aws_config["aws-config"] --> n_dep_aws_config["dep:aws-config"]
  n_aws_sdk_ses["aws-sdk-ses"] --> n_dep_aws_sdk_ses["dep:aws-sdk-ses"]
  n_default["default"] --> n_http["http"]
  n_default["default"] --> n_twilio["twilio"]
  n_default["default"] --> n_whatsapp["whatsapp"]
  n_default["default"] --> n_flowroute["flowroute"]
  n_default["default"] --> n_slack["slack"]
  n_default["default"] --> n_telegram["telegram"]
  n_default["default"] --> n_discord["discord"]
  n_default["default"] --> n_teams["teams"]
  n_default["default"] --> n_signal["signal"]
  n_default["default"] --> n_ntfy["ntfy"]
  n_discord["discord"] --> n_http["http"]
  n_flowroute["flowroute"] --> n_http["http"]
  n_http["http"] --> n_reqwest["reqwest"]
  n_http["http"] --> n_dep_infrastructure_fetcher["dep:infrastructure-fetcher"]
  n_ntfy["ntfy"] --> n_http["http"]
  n_postgres["postgres"]
  n_reqwest["reqwest"] --> n_dep_reqwest["dep:reqwest"]
  n_ses["ses"] --> n_aws_sdk_ses["aws-sdk-ses"]
  n_ses["ses"] --> n_aws_config["aws-config"]
  n_signal["signal"] --> n_http["http"]
  n_slack["slack"] --> n_http["http"]
  n_teams["teams"] --> n_http["http"]
  n_telegram["telegram"] --> n_http["http"]
  n_twilio["twilio"] --> n_http["http"]
  n_whatsapp["whatsapp"] --> n_http["http"]

Targets

KindNameSource
libinfrastructure_communication`src/lib.rs`
testintegration_tests`tests/integration_tests.rs`

Error model

No public error type was detected: no public item declares a type named *Error, and no public signature returns one.

Operational characteristics

PropertyEvidence
async public surfaceyes
async runtimeyes
database accessyes
network I/Oyes
unsafe codenone detected
environment variablesnone detected

No unsafe block, unsafe fn, unsafe impl or unsafe trait was found by the parser anywhere in this crate's source.

Configuration

No environment variable is read with a literal name anywhere in this crate. A variable whose key is computed at run time cannot be listed here, and is not claimed to be absent.

3 workspace crates depend on this one: application-communication, application-conversation, application-messaging.

Verification

KindCount
Unit tests86
Integration tests13
Examples0
Doctests0

Evidence by module. How often each public module is named by something executable.

ModuleTestsExamplesConsumers
repo1805

What the tests establish, by name:

Documentation coverage

MeasureDocumentedTotal
Public items with rustdoc1818
Public modules with a //! block11
pie showData
    title Public items with rustdoc
    "Documented" : 18
    "No rustdoc detected" : 0

Metrics

MetricValue
Rust source files24
Source lines7291
Code lines5232
Public API items18
Public modules1
Tests99
Examples0
Cargo features16
Direct runtime dependencies18
Workspace reverse dependencies3
pie showData
    title Public API by kind
    "function" : 18
pie showData
    title Rust source composition
    "Code" : 5232
    "Blank or comment" : 2059

Generation

Rendered by tools-corpus corpus readme from repository evidence alone, renderer schema 2, lexicon current. No model, network service or database was consulted. Regenerate with tools-corpus corpus readme --write; verify with --check.

All infrastructure · Manual