berrypod/test/berrypod
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
..
analytics replace analytics double-count prevention with buffer supersede 2026-02-23 14:48:50 +00:00
clients add Printify client test coverage with Req.Test stubs 2026-02-22 10:35:24 +00:00
images rename project from SimpleshopTheme to Berrypod 2026-02-18 21:23:15 +00:00
mailer namespace email settings keys per adapter 2026-02-21 19:57:23 +00:00
media rename project from SimpleshopTheme to Berrypod 2026-02-18 21:23:15 +00:00
orders add abandoned cart recovery 2026-02-24 10:02:37 +00:00
products fix flaky sqlite test contention 2026-02-20 22:54:12 +00:00
providers add Printify client test coverage with Req.Test stubs 2026-02-22 10:35:24 +00:00
stripe rename project from SimpleshopTheme to Berrypod 2026-02-18 21:23:15 +00:00
sync add Printful client test coverage with Req.Test stubs 2026-02-22 10:20:49 +00:00
theme migrate accent colours from HSL to oklch, inject theme into admin 2026-02-20 23:53:42 +00:00
webhooks rename project from SimpleshopTheme to Berrypod 2026-02-18 21:23:15 +00:00
accounts_test.exs auto-confirm admin during setup, skip email verification 2026-02-21 10:24:26 +00:00
analytics_test.exs add entry/exit pages panel to analytics dashboard 2026-02-23 21:14:24 +00:00
cart_test.exs rename project from SimpleshopTheme to Berrypod 2026-02-18 21:23:15 +00:00
mailer_test.exs add tests for email verification flag lifecycle 2026-02-21 22:43:33 +00:00
media_test.exs fix flaky sqlite test contention 2026-02-20 22:54:12 +00:00
orders_test.exs add order status lookup for customers 2026-02-24 08:40:08 +00:00
products_test.exs rename project from SimpleshopTheme to Berrypod 2026-02-18 21:23:15 +00:00
products_upsert_test.exs rename project from SimpleshopTheme to Berrypod 2026-02-18 21:23:15 +00:00
search_test.exs rename project from SimpleshopTheme to Berrypod 2026-02-18 21:23:15 +00:00
settings_test.exs migrate accent colours from HSL to oklch, inject theme into admin 2026-02-20 23:53:42 +00:00
setup_test.exs add setup onboarding page, dashboard launch checklist, provider registry 2026-02-20 00:34:06 +00:00
shipping_test.exs rename project from SimpleshopTheme to Berrypod 2026-02-18 21:23:15 +00:00
sqlite_concurrency_test.exs add SQLite concurrency tests and bench task 2026-02-22 09:23:36 +00:00
vault_test.exs rename project from SimpleshopTheme to Berrypod 2026-02-18 21:23:15 +00:00
webhooks_test.exs rename project from SimpleshopTheme to Berrypod 2026-02-18 21:23:15 +00:00