Skip to content

Add a lifecycle email for paid organizers who have gone quiet - #1457

Merged
daveearley merged 1 commit into
developfrom
feature/lapsed-payer-nudge
Oct 27, 2026
Merged

daveearley merged 1 commit into
developfrom
feature/lapsed-payer-nudge

Conversation

@daveearley

Copy link
Copy Markdown
Contributor

What

A new lifecycle email, LAPSED_PAYER ("Planning your next event?"), for organizers who sold paid tickets and then went quiet.

When it sends: once per owner, 60 days after the end of the account's most recent date with real paid sales, if:

  • no event has been created and no active date has run in the last 60 days
  • no date on the account (any status) ends in the future, so nobody mid-event or with something upcoming gets it

Lookback: 18 months, anchored on the last sold date. Unlike the other lifecycle emails, this deliberately reaches accounts that went quiet before the template was enabled (noted in .claude/rules/backend/lifecycle-emails.md).

What counts as a paid sale: the order is completed, payment was received, and it isn't fully refunded or manually created. Offline payments marked as received count. The account needs at least 2 distinct buyers, excluding its own team members' and organizers' emails, which filters out organizers testing their own checkout.

Also skipped:

  • unverified, suspended or pending-deletion accounts
  • unsubscribed owners and invited owners
  • events under spam review
  • cancelled last dates
  • deleted organizers

If the latest sold event was deleted, it falls back to the previous one.

Content:

  • CTA: the organizer's ended events list (or archived, if that event is archived), where Duplicate lives.
  • If the last event ended 3+ months ago, a paragraph mentions box office, add-ons, faster check-in and reserved seating (early access, on request).

Also in this PR

  • Every lifecycle email query now skips suspended accounts. They didn't before.
  • First names typed entirely in upper or lower case are title-cased in all lifecycle emails ("SARAH" becomes "Sarah"). Mixed-case names are left alone.

Rollout

The template starts disabled. Once enabled, the existing 25-per-type hourly cap applies. A read-only prod dry run returned 170 candidates (153 get the features paragraph), and the query took 0.62s.

Testing

  • Feature tests in LifecycleNudgeSweepServiceTest cover the send path and every exclusion above, including:
    • the 59/61-day boundaries and the 18-month limit
    • picking the latest sold date, and falling back when that event was deleted
    • partial vs full refunds
    • offline, manual, failed and zero-value orders
    • one person owning two accounts
  • The suspended-account test covers all five lifecycle emails.
  • Unit tests cover the name casing.
  • Unit and Feature suites, pint --test and tsc all pass. api-reference:export produced no diff.

LAPSED_PAYER emails the account owner once, 60 days after the end of the
account's most recent date with real paid sales, if nothing has run or been
created since and nothing is upcoming. It looks back 18 months, so it also
reaches accounts that went quiet before the template was enabled. When the
last event ended 3+ months ago it mentions features added since.

A sale counts when the order is completed, payment was received, it is not
fully refunded or manually created, and the account has at least two
distinct buyers outside its own team and organizer emails.

All lifecycle emails now skip suspended accounts and title-case first names
typed entirely in one case.
@github-actions

Copy link
Copy Markdown
Contributor

✅ E2E smoke tests: Everything passed.

Mode Result ✅ Passed ❌ Failed ⚠️ Flaky ⏭️ Skipped ⏱️ Duration
Self-hosted ✅ Passed 111 0 0 0 3m 32s

Open the run

@daveearley
daveearley merged commit 128e83d into develop Oct 27, 2026
10 checks passed
@github-actions github-actions Bot locked and limited conversation to collaborators Oct 27, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant