add activity log with order timeline and global feed
All checks were successful
deploy / deploy (push) Successful in 4m22s

Single activity_log table powering two views: chronological timeline
on each order detail page (replacing the old fulfilment card) and a
global feed at /admin/activity with tabs, category filters, search,
and pagination. Real-time via PubSub — new entries appear instantly,
nav badge updates across all admin pages.

Instrumented across all event points: Stripe webhooks, order notifier,
submission worker, fulfilment status worker, product sync worker, and
Oban exhausted-job telemetry. Contextual action buttons (retry
submission, retry sync, dismiss) with Oban unique constraints to
prevent double-enqueue. 90-day pruning via cron.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
jamey
2026-03-01 15:09:08 +00:00
parent b235219aee
commit 580a7203c9
23 changed files with 1716 additions and 54 deletions

View File

@@ -1,7 +1,7 @@
defmodule BerrypodWeb.StripeWebhookController do
use BerrypodWeb, :controller
alias Berrypod.Orders
alias Berrypod.{ActivityLog, Orders}
alias Berrypod.Orders.{OrderNotifier, OrderSubmissionWorker}
require Logger
@@ -69,6 +69,17 @@ defmodule BerrypodWeb.StripeWebhookController do
{:order_paid, order}
)
ActivityLog.log_event(
"order.created",
"Order placed — #{Berrypod.Cart.format_price(order.total)} via Stripe",
order_id: order.id,
payload: %{
total: order.total,
currency: order.currency,
payment_intent: payment_intent_id
}
)
OrderNotifier.deliver_order_confirmation(order)
# Submit to fulfilment provider
@@ -138,6 +149,14 @@ defmodule BerrypodWeb.StripeWebhookController do
case Orders.create_abandoned_cart(attrs) do
{:ok, cart} ->
Berrypod.Orders.AbandonedCartEmailWorker.enqueue(cart.id)
ActivityLog.log_event(
"abandoned_cart.created",
"Abandoned cart — #{email}, #{Berrypod.Cart.format_price(order.total)}",
order_id: order.id,
payload: %{email: email, total: order.total}
)
Logger.info("Abandoned cart recorded for #{email}, recovery email scheduled")
{:error, reason} ->