// Package eventbus is enkly's thin wrapper around RabbitMQ (via // github.com/rabbitmq/amqp091-go) for every *asynchronous*, // fire-and-forget cross-context notification — the counterpart to the // synchronous, request/response calls services make over gRPC (see // api/proto). Per-service request/response traffic (e.g. the agent // service asking billing "is this user over quota?") always uses gRPC; // RabbitMQ is reserved for events a publisher doesn't need an answer to, // mirroring the rule stated in the task: "gRPC for synchronous // communication, RabbitMQ for asynchronous communication." // // Topology: one durable topic exchange, "enkly.events". Each event is // published with a routing key of the form ".. // " (e.g. "iam.user.registered"); a consumer binds a durable // queue to the routing keys it cares about. Using a topic exchange // rather than one queue per consumer lets a new consumer be added later // (e.g. an analytics service) without touching the publisher. package eventbus // ExchangeName is the single durable topic exchange every service // publishes domain events to. const ExchangeName = "enkly.events" // Routing keys. Each constant is ".." — only the owning bounded context ever publishes to its // own keys (see each service's internal/infrastructure/eventing // package), but any service may subscribe. const ( // Published by iam (services/iam) — see internal/handlers/auth.go's // sendVerificationEmail/sendResetEmail, now decoupled from the // synchronous request path. RoutingKeyVerificationCodeIssued = "iam.user.verification_code_issued" RoutingKeyPasswordResetRequested = "iam.user.password_reset_requested" RoutingKeyUserRegistered = "iam.user.registered" RoutingKeyUserEmailVerified = "iam.user.email_verified" // Published by billing (services/billing). RoutingKeySubscriptionChanged = "billing.subscription.changed" // Published by conversation (services/conversation) — not consumed // by anything in this port of the monolith, but kept so a future // consumer (search indexing, analytics, audit) has something to // bind to without a producer-side change. RoutingKeyMessageCreated = "conversation.message.created" ) // QueueBinding names the durable queue a consumer should declare and // the routing key(s) it should bind, so every consumer's topology is // declared in one place next to the keys it reads. type QueueBinding struct { Queue string RoutingKeys []string } // NotificationQueueBindings is the notification service's subscription // (services/notification/internal/infrastructure/eventing) — every // event that results in an outbound email. var NotificationQueueBindings = QueueBinding{ Queue: "enkly.notification.verification_and_reset", RoutingKeys: []string{ RoutingKeyVerificationCodeIssued, RoutingKeyPasswordResetRequested, }, }