router

package
v1.7.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 29, 2026 License: MIT Imports: 2 Imported by: 0

Documentation

Overview

Package router implements the pure channel-routing function from the notification-preferences paper §4. Given a user's resolved preferences and a notification category, it returns the destination channel set for a single send.

The function is pure: no IO, no DB reads, no clock except the caller-supplied `now`. Composability over inheritance — the caller resolves prefs (via the preferences CRUD) and then invokes DeliveryChannels.

Phase 1 returns Email / SMS / Web only. The Channel type still declares WA + Push so the wire shape is forward-compatible, but the router never returns them — they are Phase 2 / Phase 3.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Category

type Category string

Category is one of the canonical notification categories from §3 of the paper. Categories split into two regulatory regimes:

  • transactional (security, legal, money_movement, trade_execution, account_status, system) — email always fires; SMS/WA/web/push opt-in for real-time courtesy.
  • marketing (promotional, newsletter, product_update, partner_offer, research) — per-category opt-in required by CAN-SPAM + GDPR + TCPA.
const (
	CatSecurity       Category = "security"
	CatLegal          Category = "legal"
	CatMoneyMovement  Category = "money_movement"
	CatTradeExecution Category = "trade_execution"
	CatAccountStatus  Category = "account_status"
	CatSystem         Category = "system"

	CatPromotional   Category = "promotional"
	CatNewsletter    Category = "newsletter"
	CatProductUpdate Category = "product_update"
	CatPartnerOffer  Category = "partner_offer"
	CatResearch      Category = "research"
)

type Channel

type Channel string

Channel is one of the canonical destination channels. Email + SMS + Web are wired in Phase 1; WA + Push are declared so the wire shape is stable but the router never returns them in Phase 1.

const (
	ChEmail Channel = "email"
	ChSMS   Channel = "sms"
	ChWA    Channel = "wa" // Phase 2 — never returned by Phase 1 router
	ChWeb   Channel = "web"
	ChPush  Channel = "push" // Phase 3 — never returned by Phase 1 router
)

func DeliveryChannels

func DeliveryChannels(prefs *Preferences, cat Category, now time.Time) []Channel

DeliveryChannels picks the destination channel set for a single send. Pure: no IO, no DB reads. `now` is the wall-clock instant used to evaluate quiet hours; callers pass time.Now().UTC() in production and a fixed instant in tests.

Behaviour from §4:

  • Mandatory-email categories: always include email. For real-time transactional categories, additionally include any prefs.RealtimeChannels the matrix allows AND the user has contact for.
  • Marketing categories: empty set unless the user has explicitly opted in. Respect quiet hours for promotional/partner_offer.
  • Unknown categories: panic. The paper §4 footer is explicit — "every category must be classed transactional or marketing".

type Preferences

type Preferences struct {
	UserID string
	OrgID  string

	PrimaryEmail  string
	BackupEmail   string
	PrimaryPhone  string
	WhatsAppPhone string
	LegalEmail    string

	// PreferredChannels — ordered list the user prefers for non-
	// mandatory notifications.
	PreferredChannels []Channel
	// RealtimeChannels — real-time courtesy channels for transactional
	// categories. The email leg is implicit and always fires for
	// mandatory-email categories regardless of this field.
	RealtimeChannels []Channel
	// MarketingSubscriptions — per-category opt-in. Missing key = false.
	MarketingSubscriptions map[Category]bool

	QuietHoursStart string // "21:00"
	QuietHoursEnd   string // "08:00"
	Timezone        string // IANA, e.g. "America/New_York"

	MarketingGloballyMuted bool
}

Preferences is the resolved per-(user, org) state the router reads. The CRUD layer materialises this from the notification_preferences row; the router itself never touches a database.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL