Feature: Creating Cart Service, Cart Events, Save For Later functionality, Adding Filament Views for viewing abandoned carts
This commit is contained in:
@@ -0,0 +1,128 @@
|
||||
# Cart/Checkout Recovery Strategies — Design Notes
|
||||
|
||||
**Status: open design discussion, not scoped or built.** This is a record of the
|
||||
reasoning behind an eventual "Recovery Sequences" feature, kept so the discussion doesn't
|
||||
have to be re-derived from scratch later. Nothing in this document is implemented.
|
||||
|
||||
See `docs/cart.md` for what's actually built today (the four-state cart classification,
|
||||
`CartAbandoned`/`CheckoutAbandoned` events, `DetectAbandonedCarts`).
|
||||
|
||||
---
|
||||
|
||||
## Why Abandoned Cart and Abandoned Checkout need different strategies
|
||||
|
||||
Established in `docs/cart.md`: Abandoned Cart (no order ever started) is a weak purchase-intent
|
||||
signal and often unreachable (no identity for a true guest). Abandoned Checkout (a draft order
|
||||
exists, `placed_at IS NULL`) is a strong intent signal and usually reachable, since checkout
|
||||
typically captures an email/address even for a guest.
|
||||
|
||||
That difference in intent and reachability drives genuinely different marketing strategy, not
|
||||
just a different admin filter:
|
||||
|
||||
### Abandoned Cart strategy — re-engagement, not completion
|
||||
|
||||
- **On-site retargeting first** (exit-intent popups, "still thinking it over?" banners on
|
||||
return visits) — often the only viable channel, since email may not exist yet.
|
||||
- **Ad platform retargeting** (Meta/Google dynamic remarketing) is the dominant channel here
|
||||
specifically because it works off a browser/device signal, not an email address — the one
|
||||
thing reliably available for an anonymous cart.
|
||||
- **Soft messaging** ("did you forget something?") rather than urgency-driven — intent is
|
||||
weak, so aggressive discounting is often poor ROI: it trains browsers who were never close
|
||||
to buying to expect a coupon.
|
||||
- **Longer, gentler cadence** — a single reminder around 24h, maybe a second a few days out,
|
||||
sometimes trigger-based (a price drop, back-in-stock) rather than a fixed schedule.
|
||||
|
||||
### Abandoned Checkout strategy — completion, not re-engagement
|
||||
|
||||
- **Speed matters most.** This is where the classic 1h/24h/72h recovery-email cadence lives —
|
||||
conversion drops sharply with delay, since the shopper is often still in a "was about to
|
||||
buy" mental state within the first hour.
|
||||
- **Direct, urgency-framed messaging** ("complete your order"), sometimes showing cart
|
||||
contents/total, occasionally a countdown or limited-time incentive on later touches.
|
||||
- **Discount escalation pays off here** — a small incentive (free shipping, 10% off) on the
|
||||
2nd/3rd touch is standard, because it's nudging someone who already decided to buy past
|
||||
whatever blocked them (price shock, a broken payment step, indecision on shipping cost) —
|
||||
not manufacturing demand from nothing.
|
||||
- **SMS is more viable** — checkout often captures a phone number, and the higher intent
|
||||
justifies a more direct channel than for cart-stage.
|
||||
|
||||
---
|
||||
|
||||
## The broader strategy space (beyond cadence + discount)
|
||||
|
||||
Raised as context for how far a "Recovery Sequence" feature might eventually need to flex,
|
||||
without committing to building any of it yet:
|
||||
|
||||
**Message-content strategies**
|
||||
- Social proof ("X people have this in their cart," reviews shown in the reminder)
|
||||
- Scarcity/urgency framing (low-stock count, countdown timer on an offer)
|
||||
- Personalized alternatives — a cheaper or complementary item instead of just re-showing the
|
||||
abandoned one, useful when the likely blocker was price
|
||||
|
||||
**Channel strategies**
|
||||
- Email (the baseline; nothing built yet — see `docs/cart.md`'s "Recovery Sequences" section)
|
||||
- SMS — checkout-stage specifically, opt-in required
|
||||
- Push notifications — not relevant yet given this project's storefront maturity, noted for
|
||||
completeness
|
||||
- On-site remarketing (banner/modal on the shopper's next visit) — doesn't require email at
|
||||
all, arguably the highest-value channel for Abandoned Cart specifically
|
||||
- Ad platform sync (pushing abandoned-cart product data to a custom audience for paid retargeting)
|
||||
|
||||
**Escalation/segmentation strategies**
|
||||
- Value-based branching — a high-value abandoned checkout might skip straight to a bigger
|
||||
incentive rather than waiting through a full ladder
|
||||
- Repeat-abandoner suppression — a customer who's abandoned 3+ times without ever completing
|
||||
either stops receiving emails (fatigue/spam risk) or gets a different tactic (e.g. a "what
|
||||
stopped you?" survey) instead of another discount
|
||||
- New vs. returning customer branching — a first-time visitor's abandoned cart might warrant
|
||||
"welcome discount" framing instead of a generic recovery email, since the blocker was
|
||||
likely trust/unfamiliarity rather than price
|
||||
|
||||
**Timing refinement**
|
||||
- Time-of-day/timezone-aware sending (don't fire a touch at 3am local time even if the delay
|
||||
technically elapsed)
|
||||
- Cart-content-triggered timing — a fast-moving/low-stock item might warrant an earlier, more
|
||||
urgent first touch than a cart of always-in-stock staples
|
||||
|
||||
---
|
||||
|
||||
## First-pass feature shape (discussed, not finalized)
|
||||
|
||||
An admin defines, independently per abandonment type (Abandoned Cart, Abandoned Checkout), an
|
||||
ordered sequence of **touches**. Each touch is three ideas:
|
||||
|
||||
1. **How long to wait** since the abandonment began
|
||||
2. **What offer to attach**, optional — reusing whatever `Discount` already exists in the
|
||||
system rather than inventing a new pricing concept
|
||||
3. **A label**, so staff can see what a touch represents in the admin UI
|
||||
|
||||
The system continuously re-evaluates every abandoned cart/checkout against its sequence, and
|
||||
when a cart becomes due for the next touch it hasn't had yet, that becomes a signal — this
|
||||
feature's responsibility ends there. Actually sending anything (email, SMS, on-site banner) is
|
||||
explicitly out of scope for this feature; something else, not yet designed, would consume that
|
||||
signal.
|
||||
|
||||
### What this requires that isn't built yet
|
||||
|
||||
- **A fixed "abandonment began at" timestamp**, captured once and never re-derived — a
|
||||
sequence needs to schedule touches from a stable starting point, not from `Cart::updated_at`,
|
||||
which keeps moving every time the cart (or its own bookkeeping) is written to. This is the
|
||||
same underlying issue as the known bug in `docs/cart.md`'s "Abandonment detection" section —
|
||||
fixing that bug properly (freezing the abandonment moment) is very likely a prerequisite for
|
||||
this feature, not a separate concern.
|
||||
- **Re-evaluation, not one-shot detection** — `DetectAbandonedCarts` today marks a cart
|
||||
abandoned once and stops; a sequence needs a cart to be revisited on every scheduler run to
|
||||
check "which touch, if any, is now due," for as long as it stays unrecovered.
|
||||
|
||||
### Still undecided
|
||||
|
||||
- **Which concern this belongs under.** Not `Cart` (it's not a cart-mechanics concern) —
|
||||
candidates raised: a new `Recovery` concern, or `Marketing`. Not decided.
|
||||
- **How far the touch model needs to flex.** The three-idea shape above (delay, discount,
|
||||
label) covers cadence + discount escalation cleanly, but doesn't yet accommodate channel
|
||||
choice, value-based branching, or segment targeting from the broader strategy list above.
|
||||
Whether those get folded into the touch model, layered on top some other way, or deliberately
|
||||
left out of v1 is unresolved.
|
||||
- **Whether "recovery" is cart/checkout-specific at all**, or a more general "scheduled
|
||||
customer touch based on a triggering condition" mechanism that cart/checkout abandonment
|
||||
happens to be the first use case for.
|
||||
Reference in New Issue
Block a user