package notification // Kind constants name every supported notification kind. The implementation // trims the README ยง10 catalog to the set with active producers in // the codebase; further kinds (`game.*`, `mail.dead_lettered`) require // an additive change here together with a producer. const ( KindLobbyInviteReceived = "lobby.invite.received" KindLobbyInviteRevoked = "lobby.invite.revoked" KindLobbyApplicationSubmitted = "lobby.application.submitted" KindLobbyApplicationApproved = "lobby.application.approved" KindLobbyApplicationRejected = "lobby.application.rejected" KindLobbyMembershipRemoved = "lobby.membership.removed" KindLobbyMembershipBlocked = "lobby.membership.blocked" KindLobbyRaceNameRegistered = "lobby.race_name.registered" KindLobbyRaceNamePending = "lobby.race_name.pending" KindLobbyRaceNameExpired = "lobby.race_name.expired" KindRuntimeImagePullFailed = "runtime.image_pull_failed" KindRuntimeContainerStartFailed = "runtime.container_start_failed" KindRuntimeStartConfigInvalid = "runtime.start_config_invalid" KindGameTurnReady = "game.turn.ready" KindGamePaused = "game.paused" KindDiplomailReceived = "diplomail.message.received" ) // CatalogEntry describes the per-kind delivery policy: which channels // fan out and whether the kind targets the platform admin recipient // instead of per-user accounts. type CatalogEntry struct { // Channels lists the channels this kind fans out to, in the order // rows are materialised in `notification_routes`. The closed set is // {`push`, `email`}. Channels []string // Admin reports whether the email channel targets the configured // admin recipient (`BACKEND_NOTIFICATION_ADMIN_EMAIL`) rather than // per-user accounts. Admin-targeted kinds carry an empty Recipients // slice on the producer side. Admin bool // MailTemplateID is the template_id passed to `mail.EnqueueTemplate` // for email routes. The catalog uses the kind itself by convention, // matching `mail.TemplateLoginCode`'s use of `auth.login_code`. MailTemplateID string } // catalog maps each supported kind to its delivery policy. The map is // queried by Submit and by the dispatcher worker; producers do not // inspect it directly. var catalog = map[string]CatalogEntry{ KindLobbyInviteReceived: { Channels: []string{ChannelPush, ChannelEmail}, MailTemplateID: KindLobbyInviteReceived, }, KindLobbyInviteRevoked: { Channels: []string{ChannelPush}, }, KindLobbyApplicationSubmitted: { Channels: []string{ChannelPush}, }, KindLobbyApplicationApproved: { Channels: []string{ChannelPush, ChannelEmail}, MailTemplateID: KindLobbyApplicationApproved, }, KindLobbyApplicationRejected: { Channels: []string{ChannelPush, ChannelEmail}, MailTemplateID: KindLobbyApplicationRejected, }, KindLobbyMembershipRemoved: { Channels: []string{ChannelPush, ChannelEmail}, MailTemplateID: KindLobbyMembershipRemoved, }, KindLobbyMembershipBlocked: { Channels: []string{ChannelPush, ChannelEmail}, MailTemplateID: KindLobbyMembershipBlocked, }, KindLobbyRaceNameRegistered: { Channels: []string{ChannelPush}, }, KindLobbyRaceNamePending: { Channels: []string{ChannelPush, ChannelEmail}, MailTemplateID: KindLobbyRaceNamePending, }, KindLobbyRaceNameExpired: { Channels: []string{ChannelPush}, }, KindRuntimeImagePullFailed: { Channels: []string{ChannelEmail}, Admin: true, MailTemplateID: KindRuntimeImagePullFailed, }, KindRuntimeContainerStartFailed: { Channels: []string{ChannelEmail}, Admin: true, MailTemplateID: KindRuntimeContainerStartFailed, }, KindRuntimeStartConfigInvalid: { Channels: []string{ChannelEmail}, Admin: true, MailTemplateID: KindRuntimeStartConfigInvalid, }, KindGameTurnReady: { Channels: []string{ChannelPush}, }, KindGamePaused: { Channels: []string{ChannelPush}, }, KindDiplomailReceived: { Channels: []string{ChannelPush}, }, } // LookupCatalog returns the per-kind policy and a boolean reporting // whether the kind exists. Callers (Submit, Worker) branch on the // boolean rather than receiving a sentinel error. func LookupCatalog(kind string) (CatalogEntry, bool) { entry, ok := catalog[kind] return entry, ok } // SupportedKinds returns the closed kind set in deterministic order. // The function exists to back tests and the migration CHECK constraint // audit; it is not on the hot path. func SupportedKinds() []string { return []string{ KindLobbyInviteReceived, KindLobbyInviteRevoked, KindLobbyApplicationSubmitted, KindLobbyApplicationApproved, KindLobbyApplicationRejected, KindLobbyMembershipRemoved, KindLobbyMembershipBlocked, KindLobbyRaceNameRegistered, KindLobbyRaceNamePending, KindLobbyRaceNameExpired, KindRuntimeImagePullFailed, KindRuntimeContainerStartFailed, KindRuntimeStartConfigInvalid, KindGameTurnReady, KindGamePaused, KindDiplomailReceived, } }