PhoenixKitEcommerce.Notifications (PhoenixKitEcommerce v0.2.0)

Copy Markdown View Source

Shop notifications: who hears about an order or an import, and when.

Sends go through core's notification layer, so each recipient's own per-type preferences and delivery channels (in-app inbox, email, Telegram, digest cadence) apply. This module only decides the audience and the copy.

Recipients

admin_recipients/0 unions three sources, because no single one is complete:

  • holders of the relevant permission key (users_with_permission/1)
  • Owner-role holders, whose access is implicit and who therefore have no permission rows at all
  • holders of the "*" superadmin key, likewise absent from a key-specific query

A resolver that queried only the first would miss the primary operator of a default install — the person most likely to want the notification.

Failure is never fatal

Every send is wrapped: a notification is a message about a committed fact, and must not be able to undo it. Order placement in particular runs this after the conversion transaction commits.

Summary

Functions

Everyone who should hear about shop operations: holders of key, unioned with Owner-role holders and "*" superadmins.

Storefront signal: an item landed in a cart.

Storefront signal: a buyer reached the checkout page with a valid cart. Fires once per cart (atomic claim), only when the toggle is on.

Notifies the admin who started an import that it finished.

Notifies the initiator that an import failed.

Notifies shop operators that an order was placed, and (separately) the customer that theirs was confirmed.

Recipients for storefront signals: the configured recipient list (shop_notification_recipients), or every shop admin when unset/empty.

Functions

admin_recipients(key)

Everyone who should hear about shop operations: holders of key, unioned with Owner-role holders and "*" superadmins.

cart_item_added(cart, item, product)

Storefront signal: an item landed in a cart.

Emits shop.cart_first_item_added once per cart (atomic claim) when that toggle is on; otherwise emits shop.cart_item_added per add when the every-add toggle is on. A first add never produces both.

checkout_started(cart)

Storefront signal: a buyer reached the checkout page with a valid cart. Fires once per cart (atomic claim), only when the toggle is on.

import_completed(import_log, stats)

Notifies the admin who started an import that it finished.

Job-level only: one message per import carrying aggregate counts, never one per row — a 10k-row import must not produce 10k notifications.

import_failed(import_log, reason)

Notifies the initiator that an import failed.

Call ONLY on the terminal attempt: Oban retries a failed job, and notifying on every attempt turns one transient failure into three alerts followed by a success.

order_placed(order)

Notifies shop operators that an order was placed, and (separately) the customer that theirs was confirmed.

Best-effort by construction — see the module doc.

shop_recipients()

Recipients for storefront signals: the configured recipient list (shop_notification_recipients), or every shop admin when unset/empty.

Stored as %{"uuids" => [...]} rather than a bare list — core's value_json column casts through an Ecto :map field, which rejects a top-level list at the changeset.

The stored list is re-checked against shop.manage_carts holders on every send, not only when the admin saved it: the setting is a snapshot of who was an operator that day, and revoking someone's shop access has to stop the cart-activity feed too — those messages carry what visitors are shopping for and what their carts are worth. Fails closed, since admin_recipients/1 rescues to [].