berrypod/lib/berrypod_web/controllers
jamey 2f4cd81f98 add abandoned cart recovery
When a Stripe checkout session expires without payment, if the customer
entered their email, we record an AbandonedCart and schedule a single
plain-text recovery email (1h delay via Oban).

Privacy design:
- feature is off by default; shop owner opts in via admin settings
- only contacts customers who entered their email at Stripe checkout
- single email, never more (emailed_at timestamp gate)
- suppression list blocks repeat contact; one-click unsubscribe via
  signed token (/unsubscribe/:token)
- records pruned after 30 days (nightly Oban cron)
- no tracking pixels, no redirected links, no HTML

Legal notes:
- custom_text added to Stripe session footer when recovery is on
- UK PECR soft opt-in; EU legitimate interests both satisfied by this design

Files:
- migration: abandoned_carts + email_suppressions tables
- schemas: AbandonedCart, EmailSuppression
- context: Orders.create_abandoned_cart, check_suppression, add_suppression,
  has_recent_paid_order?, get_abandoned_cart_by_session, mark_abandoned_cart_emailed
- workers: AbandonedCartEmailWorker (checkout queue), AbandonedCartPruneWorker (cron)
- notifier: OrderNotifier.deliver_cart_recovery/3
- webhook: extended checkout.session.expired handler
- controller: UnsubscribeController, admin settings toggle
- tests: 28 new tests across context, workers, and controller

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-24 10:02:37 +00:00
..
page_html rename project from SimpleshopTheme to Berrypod 2026-02-18 21:23:15 +00:00
admin_controller.ex rename project from SimpleshopTheme to Berrypod 2026-02-18 21:23:15 +00:00
analytics_export_controller.ex add analytics CSV export 2026-02-24 09:37:45 +00:00
cart_controller.ex rename project from SimpleshopTheme to Berrypod 2026-02-18 21:23:15 +00:00
checkout_controller.ex add abandoned cart recovery 2026-02-24 10:02:37 +00:00
error_html.ex improve error pages: minimal version when site not live 2026-02-20 22:19:21 +00:00
error_json.ex rename project from SimpleshopTheme to Berrypod 2026-02-18 21:23:15 +00:00
error_preview_controller.ex rename project from SimpleshopTheme to Berrypod 2026-02-18 21:23:15 +00:00
health_controller.ex rename project from SimpleshopTheme to Berrypod 2026-02-18 21:23:15 +00:00
image_controller.ex rename project from SimpleshopTheme to Berrypod 2026-02-18 21:23:15 +00:00
order_lookup_controller.ex add order status lookup for customers 2026-02-24 08:40:08 +00:00
page_controller.ex rename project from SimpleshopTheme to Berrypod 2026-02-18 21:23:15 +00:00
page_html.ex rename project from SimpleshopTheme to Berrypod 2026-02-18 21:23:15 +00:00
seo_controller.ex add canonical URLs, robots.txt, and sitemap.xml 2026-02-23 21:47:35 +00:00
setup_controller.ex fix recovery login crash for users with password set 2026-02-21 22:52:46 +00:00
stripe_webhook_controller.ex add abandoned cart recovery 2026-02-24 10:02:37 +00:00
unsubscribe_controller.ex add abandoned cart recovery 2026-02-24 10:02:37 +00:00
user_session_controller.ex rename project from SimpleshopTheme to Berrypod 2026-02-18 21:23:15 +00:00
webhook_controller.ex rename project from SimpleshopTheme to Berrypod 2026-02-18 21:23:15 +00:00