newsletter: dev/deploy env wiring (PROFILE_URL, log sender), CampaignEvent.URL, plan + status docs

This commit is contained in:
mats committed 2026-08-05 15:07:39 +02:00
1 parent 0db9705063
commit 4aa9c91bc7
1 file changed
+42 -14
+42 -14
View File
@@ -72,15 +72,26 @@ const (
TrackCart Type = "track.cart" // 3,4 — add to / remove from cart
TrackImpression Type = "track.impression" // 5 — impression
TrackAction Type = "track.action" // 6 — custom action (wishlist, etc.)
TrackPageView Type = "track.page_view"
TrackPageEngaged Type = "track.page_engaged"
TrackPageAction Type = "track.page_action"
TrackExperiment Type = "track.experiment"
// TrackPurchase — cut 23. Post-checkout funnel closure; emitted by
// event_handlers.go::TrackPurchase on a purchase request. Replaces
// 5 hand-written `pevent.Type("track.purchase")` literals with this
// typed constant.
TrackPurchase Type = "track.purchase"
TrackPageView Type = "track.page_view"
TrackPageEngaged Type = "track.page_engaged"
TrackPageAction Type = "track.page_action"
TrackExperiment Type = "track.experiment"
// TrackPurchase — cut 23. Post-checkout funnel closure; emitted by
// event_handlers.go::TrackPurchase on a purchase request. Replaces
// 5 hand-written `pevent.Type("track.purchase")` literals with this
// typed constant.
TrackPurchase Type = "track.purchase"
// Newsletter campaign attribution (review 3.8). Producer: the order
// service's MailerSend webhook receiver (cmd/order/newsletter-webhook.go)
// when MailerSend reports an open / click for a newsletter send. Consumer:
// slask-tracking (pkg/events/rabbit-tracking.go) — feeds per-send
// open/click rates for the backoffice delivery log. Payload is an
// event.CampaignEvent. Wire routing keys `track.campaign_open` /
// `track.campaign_click` ride the existing `track.*` pattern on the
// catalog exchange.
TrackCampaignOpen Type = "track.campaign_open"
TrackCampaignClick Type = "track.campaign_click"
// Wishlist attribution (W6d of docs/plan-wishlist-favorites.md).
// Producers: profile service (share-page read) and cart service
@@ -105,13 +116,31 @@ const (
// `track.*` pattern — so slask-tracking's existing `track.*` binding
// does not pick them up. Payload: event.WishlistMutationEvent (profile)
// / event.CartToWishlistEvent (cart). See docs/amqp-topics.md.
WishlistCreated Type = "wishlist.created" // explicit user-created list (not the implicit default materialisation)
WishlistItemAdded Type = "wishlist.item_added" // one per SKU added (single-add and batch paths)
WishlistCreated Type = "wishlist.created" // explicit user-created list (not the implicit default materialisation)
WishlistItemAdded Type = "wishlist.item_added" // one per SKU added (single-add and batch paths)
WishlistItemRemoved Type = "wishlist.item_removed"
WishlistShared Type = "wishlist.shared" // share (re)generated — token itself never leaves the service
CartToWishlist Type = "cart.to_wishlist" // cart → list conversion (cart service)
WishlistShared Type = "wishlist.shared" // share (re)generated — token itself never leaves the service
CartToWishlist Type = "cart.to_wishlist" // cart → list conversion (cart service)
)
// CampaignEvent is the payload for the newsletter campaign attribution
// events (TrackCampaignOpen / TrackCampaignClick). Deliberately pseudonymous
// (C5): it carries the send id (the `newsletter:{sendID}` MailerSend tag
// parsed from the webhook) and a sha256 hex hash of the recipient email,
// never the address itself. At is unix seconds (MailerSend's created_at;
// falls back to arrival time when absent).
//
// URL is the link that was clicked (TrackCampaignClick only): the webhook
// receiver stamps the MailerSend click URL so slask-tracking can aggregate
// top-clicked links per send. Empty for opens and for clicks whose payload
// carried no URL.
type CampaignEvent struct {
SendID string `json:"sendId"`
EmailHash string `json:"emailHash"`
At int64 `json:"at,omitempty"`
URL string `json:"url,omitempty"`
}
// WishlistEvent is the payload for the wishlist attribution events
// (WishlistViewed / WishlistToCart). Deliberately lean: list id + catalog
// item ids only — no owner id, no list name, no share token, so the
@@ -184,7 +213,6 @@ func IsKnownType(s string) bool {
return false
}
// Event is the one envelope. Payload is per-Type, agreed between producer and
// consumer (json.RawMessage, not a god-struct). A nil Payload means "the subject
// changed; fetch the latest state."