Skip to content

Fixed free welcome emails being sent to new paid members#25664

Merged
cmraible merged 5 commits intomainfrom
chris-ny-857-free-member-welcome-email-is-sent-to-new-paid-members
Dec 10, 2025
Merged

Fixed free welcome emails being sent to new paid members#25664
cmraible merged 5 commits intomainfrom
chris-ny-857-free-member-welcome-email-is-sent-to-new-paid-members

Conversation

@cmraible
Copy link
Collaborator

@cmraible cmraible commented Dec 9, 2025

closes https://linear.app/ghost/issue/NY-857/free-member-welcome-email-is-sent-to-new-paid-members

Currently if free welcome emails are enabled, and a new member signs up for a paid subscription, they will receive the free welcome email in error. This is because new paid members are initially created in the free status, until the Stripe subscription is fully processed, at which point they transition to paid.

This fixes the bug by opting to skip sending the welcome email if the member has a stripeCustomer attached, which indicates that the member at least intends to become a paid member.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 9, 2025

Walkthrough

The PR removes the default memberStatus in MemberWelcomeEmailService.send() (now async send({member, memberStatus})). Member creation now sets status: 'free' on MemberCreatedEvent payloads; free welcome emails and outbox entries are only created when stripeCustomer is absent (isFreeSignup). The outbox handler forwards payload.status to the welcome-email service. Tests were updated to include status: 'free' and a new unit test verifies members with a stripeCustomer do not create an outbox entry.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Verify MemberRepository gating: stripeCustomer/isFreeSignup logic and Outbox.add conditions.
  • Check MemberCreatedEvent payloads include status consistently across creation paths.
  • Confirm outbox handler forwards payload.status and that all events populate it.
  • Review updated tests (integration + unit) for correct assertions covering free vs paid signup.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: preventing free welcome emails from being sent to new paid members, which is the core objective of the pull request.
Description check ✅ Passed The PR description directly addresses the bug fix and explains the root cause, the solution approach, and references the issue being resolved.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch chris-ny-857-free-member-welcome-email-is-sent-to-new-paid-members

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Contributor

github-actions bot commented Dec 9, 2025

Ember E2E Tests Failed

To view the Playwright test report locally, run:

REPORT_DIR=$(mktemp -d) && gh run download 20050501701 -n playwright-report-ember -D "$REPORT_DIR" && npx playwright show-report "$REPORT_DIR"

1 similar comment
@github-actions
Copy link
Contributor

github-actions bot commented Dec 9, 2025

Ember E2E Tests Failed

To view the Playwright test report locally, run:

REPORT_DIR=$(mktemp -d) && gh run download 20050501701 -n playwright-report-ember -D "$REPORT_DIR" && npx playwright show-report "$REPORT_DIR"

@github-actions
Copy link
Contributor

github-actions bot commented Dec 9, 2025

Ember E2E Tests Failed

To view the Playwright test report locally, run:

REPORT_DIR=$(mktemp -d) && gh run download 20077702586 -n playwright-report-ember -D "$REPORT_DIR" && npx playwright show-report "$REPORT_DIR"

1 similar comment
@github-actions
Copy link
Contributor

github-actions bot commented Dec 9, 2025

Ember E2E Tests Failed

To view the Playwright test report locally, run:

REPORT_DIR=$(mktemp -d) && gh run download 20077702586 -n playwright-report-ember -D "$REPORT_DIR" && npx playwright show-report "$REPORT_DIR"

@cmraible cmraible marked this pull request as ready for review December 9, 2025 23:15
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
ghost/core/core/server/services/members/members-api/repositories/MemberRepository.js (1)

347-389: Free welcome email gating on stripeCustomer matches intent

The updated conditions on outbox creation and StartOutboxProcessingEvent:

  • Only run when the free welcome template is active, and
  • Skip entirely when stripeCustomer is present,

are a good fit for avoiding free welcome emails on paid signups while preserving the free path behavior.

You might slightly tighten the coupling to persisted state by deriving the payload status instead of hardcoding it:

-                        payload: JSON.stringify({
+                        payload: JSON.stringify({
                             memberId: newMember.id,
                             email: newMember.get('email'),
                             name: newMember.get('name'),
                             source,
-                            timestamp,
-                            memberStatus: 'free'
+                            timestamp,
+                            memberStatus: newMember.get('status')
                         })

This keeps memberStatus in the payload consistent with whatever status we actually wrote to the member record (currently still 'free' for this path).

ghost/core/test/integration/jobs/process-outbox.test.js (1)

79-239: Outbox job fixtures correctly updated with memberStatus

Updating all MemberCreatedEvent test payloads to include memberStatus: 'free' (and ensuring name is present) keeps these integration tests in sync with the new handler and service signature.

Optionally, you could add a simple assertion on memberStatus in one of the tests that inspects payloads (similar to the member‑welcome integration tests) to catch any future regressions, but the current coverage is already functionally sound.

ghost/core/test/integration/services/member-welcome-emails.test.js (1)

71-82: Integration coverage for memberStatus in welcome email flow looks good

Asserting payload.memberStatus === 'free' on member creation and adding memberStatus: 'free' to the outbox entries used in the inactive/no‑template scenarios ensures the integration path matches the updated service contract and handler behavior.

If you want slightly stronger guarantees, you could also assert memberStatus in the inactive/no‑template tests when inspecting the stored payload, but it’s not strictly necessary given the existing checks.

Also applies to: 191-203, 219-226

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5a8a9c0 and f47102f.

📒 Files selected for processing (6)
  • ghost/core/core/server/services/member-welcome-emails/service.js (1 hunks)
  • ghost/core/core/server/services/members/members-api/repositories/MemberRepository.js (3 hunks)
  • ghost/core/core/server/services/outbox/handlers/member-created.js (1 hunks)
  • ghost/core/test/integration/jobs/process-outbox.test.js (8 hunks)
  • ghost/core/test/integration/services/member-welcome-emails.test.js (3 hunks)
  • ghost/core/test/unit/server/services/members/members-api/repositories/MemberRepository.test.js (1 hunks)
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: troyciesco
Repo: TryGhost/Ghost PR: 25288
File: ghost/core/core/server/services/member-welcome-emails/jobs/lib/process-entries.js:46-64
Timestamp: 2025-11-10T23:10:17.470Z
Learning: In ghost/core/core/server/services/member-welcome-emails/jobs/lib/process-entries.js and the outbox processing flow, entries are marked as PROCESSING before being processed. If a failure occurs after email send but before deletion, the entry remains stuck in PROCESSING state (not reprocessed). This intentional design prevents duplicate emails. Handling stuck PROCESSING entries is planned for a separate PR.
📚 Learning: 2025-11-10T23:10:17.470Z
Learnt from: troyciesco
Repo: TryGhost/Ghost PR: 25288
File: ghost/core/core/server/services/member-welcome-emails/jobs/lib/process-entries.js:46-64
Timestamp: 2025-11-10T23:10:17.470Z
Learning: In ghost/core/core/server/services/member-welcome-emails/jobs/lib/process-entries.js and the outbox processing flow, entries are marked as PROCESSING before being processed. If a failure occurs after email send but before deletion, the entry remains stuck in PROCESSING state (not reprocessed). This intentional design prevents duplicate emails. Handling stuck PROCESSING entries is planned for a separate PR.

Applied to files:

  • ghost/core/test/integration/jobs/process-outbox.test.js
  • ghost/core/core/server/services/member-welcome-emails/service.js
  • ghost/core/test/integration/services/member-welcome-emails.test.js
  • ghost/core/core/server/services/members/members-api/repositories/MemberRepository.js
  • ghost/core/test/unit/server/services/members/members-api/repositories/MemberRepository.test.js
  • ghost/core/core/server/services/outbox/handlers/member-created.js
📚 Learning: 2025-10-30T17:13:26.190Z
Learnt from: sam-lord
Repo: TryGhost/Ghost PR: 25303
File: ghost/core/core/server/services/email-service/BatchSendingService.js:19-19
Timestamp: 2025-10-30T17:13:26.190Z
Learning: In ghost/core/core/server/services/email-service/BatchSendingService.js and similar files in the Ghost codebase, prefer using `{...options}` spread syntax without explicit guards like `...(options || {})` when spreading potentially undefined objects, as the maintainer prefers cleaner syntax over defensive patterns when the behavior is safe.

Applied to files:

  • ghost/core/core/server/services/member-welcome-emails/service.js
  • ghost/core/core/server/services/outbox/handlers/member-created.js
📚 Learning: 2025-03-13T09:00:20.205Z
Learnt from: mike182uk
Repo: TryGhost/Ghost PR: 22471
File: apps/admin-x-activitypub/src/utils/pending-activity.ts:13-71
Timestamp: 2025-03-13T09:00:20.205Z
Learning: The pending activity utilities in the Ghost ActivityPub module are covered by tests in the file `apps/admin-x-activitypub/test/unit/utils/pending-activity.ts`.

Applied to files:

  • ghost/core/test/integration/services/member-welcome-emails.test.js
🧬 Code graph analysis (3)
ghost/core/test/integration/services/member-welcome-emails.test.js (3)
ghost/core/test/integration/jobs/process-outbox.test.js (1)
  • assert (2-2)
ghost/core/test/unit/server/services/members/members-api/repositories/MemberRepository.test.js (3)
  • assert (2-2)
  • payload (558-558)
  • payload (624-624)
ghost/core/core/server/services/outbox/jobs/lib/process-entries.js (1)
  • payload (51-51)
ghost/core/test/unit/server/services/members/members-api/repositories/MemberRepository.test.js (2)
ghost/core/core/server/services/member-welcome-emails/service.js (1)
  • config (5-5)
ghost/core/core/server/services/members/members-api/repositories/MemberRepository.js (1)
  • config (11-11)
ghost/core/core/server/services/outbox/handlers/member-created.js (3)
ghost/core/core/server/services/outbox/jobs/lib/process-outbox.js (1)
  • memberWelcomeEmailService (7-7)
ghost/core/test/integration/services/member-welcome-emails.test.js (2)
  • payload (76-76)
  • payload (147-147)
ghost/core/test/unit/server/services/members/members-api/repositories/MemberRepository.test.js (2)
  • payload (558-558)
  • payload (624-624)
🔇 Additional comments (2)
ghost/core/test/unit/server/services/members/members-api/repositories/MemberRepository.test.js (1)

673-715: Good regression test for paid signup path skipping free welcome email

The new test that exercises create with a stripeCustomer payload and asserts that Outbox.add is not called directly guards the main regression risk this PR addresses, while avoiding unrelated Stripe wiring via stubs on linkSubscription/upsertCustomer. This is a solid addition to the suite.

ghost/core/core/server/services/member-welcome-emails/service.js (1)

44-92: Making memberStatus explicit in send is appropriate

Requiring memberStatus in send({member, memberStatus}) aligns with the new split of templates by member status and prevents accidental reliance on a 'free' default. Combined with the outbox payload updates, this keeps the contract clear and ensures misconfigured statuses fail fast via the existing NO_MEMBER_WELCOME_EMAIL / inactive‑template checks.

Copy link
Collaborator Author

@cmraible cmraible left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couple minor naming notes to self

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
ghost/core/core/server/services/outbox/handlers/member-created.js (1)

6-8: LGTM – Change aligns with the new payload structure.

The handler now correctly reads status from the payload instead of using a hardcoded value. Based on the learnings and past review discussion, the backwards compatibility concern was addressed by the feature being behind a private labs flag.

Optional simplification: You previously suggested removing the separate memberStatus parameter since the status is now in the payload. If the memberWelcomeEmailService.api.send method can read status directly from the member object, you could simplify to:

-await memberWelcomeEmailService.api.send({member: payload, memberStatus: payload.status});
+await memberWelcomeEmailService.api.send({member: payload});

This would eliminate the redundancy of passing the same data twice.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f47102f and 332aec8.

📒 Files selected for processing (4)
  • ghost/core/core/server/services/members/members-api/repositories/MemberRepository.js (3 hunks)
  • ghost/core/core/server/services/outbox/handlers/member-created.js (1 hunks)
  • ghost/core/test/integration/jobs/process-outbox.test.js (8 hunks)
  • ghost/core/test/integration/services/member-welcome-emails.test.js (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • ghost/core/test/integration/services/member-welcome-emails.test.js
  • ghost/core/test/integration/jobs/process-outbox.test.js
🧰 Additional context used
🧠 Learnings (9)
📓 Common learnings
Learnt from: troyciesco
Repo: TryGhost/Ghost PR: 25288
File: ghost/core/core/server/services/member-welcome-emails/jobs/lib/process-entries.js:46-64
Timestamp: 2025-11-10T23:10:17.470Z
Learning: In ghost/core/core/server/services/member-welcome-emails/jobs/lib/process-entries.js and the outbox processing flow, entries are marked as PROCESSING before being processed. If a failure occurs after email send but before deletion, the entry remains stuck in PROCESSING state (not reprocessed). This intentional design prevents duplicate emails. Handling stuck PROCESSING entries is planned for a separate PR.
📚 Learning: 2025-11-10T23:10:17.470Z
Learnt from: troyciesco
Repo: TryGhost/Ghost PR: 25288
File: ghost/core/core/server/services/member-welcome-emails/jobs/lib/process-entries.js:46-64
Timestamp: 2025-11-10T23:10:17.470Z
Learning: In ghost/core/core/server/services/member-welcome-emails/jobs/lib/process-entries.js and the outbox processing flow, entries are marked as PROCESSING before being processed. If a failure occurs after email send but before deletion, the entry remains stuck in PROCESSING state (not reprocessed). This intentional design prevents duplicate emails. Handling stuck PROCESSING entries is planned for a separate PR.

Applied to files:

  • ghost/core/core/server/services/outbox/handlers/member-created.js
  • ghost/core/core/server/services/members/members-api/repositories/MemberRepository.js
📚 Learning: 2025-10-30T17:13:26.190Z
Learnt from: sam-lord
Repo: TryGhost/Ghost PR: 25303
File: ghost/core/core/server/services/email-service/BatchSendingService.js:19-19
Timestamp: 2025-10-30T17:13:26.190Z
Learning: In ghost/core/core/server/services/email-service/BatchSendingService.js and similar files in the Ghost codebase, prefer using `{...options}` spread syntax without explicit guards like `...(options || {})` when spreading potentially undefined objects, as the maintainer prefers cleaner syntax over defensive patterns when the behavior is safe.

Applied to files:

  • ghost/core/core/server/services/outbox/handlers/member-created.js
📚 Learning: 2025-06-10T11:07:10.800Z
Learnt from: kevinansfield
Repo: TryGhost/Ghost PR: 23770
File: apps/admin-x-settings/src/components/settings/email/newsletters/NewsletterDetailModalLabs.tsx:435-450
Timestamp: 2025-06-10T11:07:10.800Z
Learning: In Ghost's newsletter customization features, when promoting a feature from alpha to beta status, the feature flag guards are updated to make the feature available under both the `emailCustomization` (beta) and `emailCustomizationAlpha` (alpha) flags. This is done by either removing conditional guards entirely when the component is already behind both flags, or by updating conditionals to check for either flag.

Applied to files:

  • ghost/core/core/server/services/outbox/handlers/member-created.js
📚 Learning: 2025-08-11T19:39:00.428Z
Learnt from: kevinansfield
Repo: TryGhost/Ghost PR: 24651
File: ghost/core/test/utils/urlUtils.js:53-57
Timestamp: 2025-08-11T19:39:00.428Z
Learning: In Ghost's test utilities, when fixing specific issues like async behavior, it's preferred to maintain existing error handling patterns (even if suboptimal) to keep PRs focused on their primary objective. Error handling improvements can be addressed in separate, dedicated PRs.

Applied to files:

  • ghost/core/core/server/services/outbox/handlers/member-created.js
📚 Learning: 2025-06-13T11:57:58.226Z
Learnt from: kevinansfield
Repo: TryGhost/Ghost PR: 23824
File: ghost/core/core/server/services/email-service/email-templates/partials/styles.hbs:919-926
Timestamp: 2025-06-13T11:57:58.226Z
Learning: In `ghost/core/core/server/services/email-service/email-templates/partials/styles.hbs`, some style blocks (e.g., `.latest-post p` and `.latest-post p a`) still use the legacy colour `#73818c` on purpose; they are later overridden by `emailCustomization` feature rules, as noted by inline TODO comments. These occurrences should not be flagged as inconsistencies.

Applied to files:

  • ghost/core/core/server/services/outbox/handlers/member-created.js
📚 Learning: 2025-02-03T17:14:37.367Z
Learnt from: kevinansfield
Repo: TryGhost/Ghost PR: 22101
File: ghost/core/core/server/api/endpoints/utils/serializers/output/utils/post-gating.js:110-117
Timestamp: 2025-02-03T17:14:37.367Z
Learning: The potential issues with gated content blocks (lack of migration path, race conditions during flag transitions, content visibility when disabled) are accepted trade-offs during the early testing phase of the contentVisibility labs feature.

Applied to files:

  • ghost/core/core/server/services/outbox/handlers/member-created.js
📚 Learning: 2025-10-09T15:31:06.587Z
Learnt from: kevinansfield
Repo: TryGhost/Ghost PR: 25118
File: apps/portal/src/actions.js:160-173
Timestamp: 2025-10-09T15:31:06.587Z
Learning: When reviewing PRs that introduce feature-flagged changes (e.g., `labs?.membersSigninOTCAlpha`), avoid suggesting modifications to non-flagged code paths unless they're directly related to the PR's objectives. Keep the scope focused on the feature-flag-specific changes only.

Applied to files:

  • ghost/core/core/server/services/outbox/handlers/member-created.js
📚 Learning: 2025-10-09T08:10:18.956Z
Learnt from: rob-ghost
Repo: TryGhost/Ghost PR: 25075
File: ghost/admin/app/services/whats-new.js:77-83
Timestamp: 2025-10-09T08:10:18.956Z
Learning: In ghost/admin/app/services/whats-new.js, reusing `this._whatsNewSettings` (initialized once in `init()`) when persisting defaults for new users without `lastSeenDate` is acceptable. The team is aware that this means sequential logins by different admins in the same tab could share the service initialization timestamp, but this tradeoff is not a concern for their use case.

Applied to files:

  • ghost/core/core/server/services/outbox/handlers/member-created.js
🧬 Code graph analysis (1)
ghost/core/core/server/services/outbox/handlers/member-created.js (3)
ghost/core/core/server/services/outbox/jobs/lib/process-outbox.js (1)
  • memberWelcomeEmailService (7-7)
ghost/core/test/integration/services/member-welcome-emails.test.js (2)
  • payload (76-76)
  • payload (147-147)
ghost/core/test/unit/server/services/members/members-api/repositories/MemberRepository.test.js (2)
  • payload (558-558)
  • payload (624-624)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: Legacy tests (Node 22.18.0, mysql8)
  • GitHub Check: Legacy tests (Node 22.18.0, sqlite3)
  • GitHub Check: Acceptance tests (Node 22.18.0, sqlite3)
  • GitHub Check: Ghost-CLI tests
  • GitHub Check: Acceptance tests (Node 22.18.0, mysql8)
  • GitHub Check: Unit tests (Node 22.18.0)
  • GitHub Check: Lint
  • GitHub Check: Build & Push Docker Image
🔇 Additional comments (2)
ghost/core/core/server/services/members/members-api/repositories/MemberRepository.js (2)

358-376: LGTM – Conditional logic correctly gates free welcome emails.

The gating logic ensures the free welcome email is only sent when:

  1. The free welcome email feature is active
  2. The member is signing up for free (no stripeCustomer)

This directly addresses the PR objective of preventing free welcome emails from being sent to new paid members. The status: 'free' field in the payload is correct since this code path is only reached for free signups.


387-389: LGTM – Event dispatch is consistently gated.

The StartOutboxProcessingEvent is only dispatched when an outbox entry has been created, maintaining consistency with the gating logic at line 361. This ensures processing is only triggered for free member signups.

@cmraible cmraible force-pushed the chris-ny-857-free-member-welcome-email-is-sent-to-new-paid-members branch from 5b45a25 to 67dc363 Compare December 9, 2025 23:53
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
ghost/core/test/integration/services/member-welcome-emails.test.js (1)

219-226: Consistent payload shape for no‑template scenario

This payload mirrors the inactive‑template test (including name and status: 'free'), keeping both branches consistent with the live outbox payload.

🧹 Nitpick comments (3)
ghost/core/test/integration/services/member-welcome-emails.test.js (1)

196-203: Manual outbox payload updated for new status field

Including both name and status: 'free' in the payload mirrors what MemberRepository.create now emits, so this inactive‑template path will exercise the same code as real events.

If this payload shape changes again, you may want a small helper to build MemberCreatedEvent payloads for tests, to avoid having to update multiple literals.

ghost/core/test/unit/server/services/members/members-api/repositories/MemberRepository.test.js (1)

673-715: Good coverage for paid‑signup (stripeCustomer) path

This test accurately exercises the new behavior: when stripeCustomer is present, no MemberCreatedEvent outbox entry is created for the free welcome email, even though the inbox config and template are active.

You could also assert that repo.upsertCustomer / repo.linkSubscription were called to ensure the paid‑signup flow still runs while the free welcome email is skipped.

ghost/core/core/server/services/members/members-api/repositories/MemberRepository.js (1)

347-390: Free welcome email correctly gated on non‑Stripe signups

The new isFreeSignup = !stripeCustomer flag and the isFreeWelcomeEmailActive && isFreeSignup checks around both Outbox.add and StartOutboxProcessingEvent cleanly prevent free welcome emails from being queued for paid (Stripe) signups, while preserving the behavior for true free signups.

Instead of hard‑coding status: 'free' in the payload, consider deriving it from the member, e.g.:

status: newMember.get('status')

or from memberStatusData.status. That keeps the payload in sync if the initial status logic ever changes (for example, if additional non‑paid statuses are introduced) and avoids encoding 'free' in multiple places.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5b45a25 and 67dc363.

📒 Files selected for processing (6)
  • ghost/core/core/server/services/member-welcome-emails/service.js (1 hunks)
  • ghost/core/core/server/services/members/members-api/repositories/MemberRepository.js (3 hunks)
  • ghost/core/core/server/services/outbox/handlers/member-created.js (1 hunks)
  • ghost/core/test/integration/jobs/process-outbox.test.js (8 hunks)
  • ghost/core/test/integration/services/member-welcome-emails.test.js (3 hunks)
  • ghost/core/test/unit/server/services/members/members-api/repositories/MemberRepository.test.js (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • ghost/core/core/server/services/member-welcome-emails/service.js
  • ghost/core/test/integration/jobs/process-outbox.test.js
  • ghost/core/core/server/services/outbox/handlers/member-created.js
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: troyciesco
Repo: TryGhost/Ghost PR: 25288
File: ghost/core/core/server/services/member-welcome-emails/jobs/lib/process-entries.js:46-64
Timestamp: 2025-11-10T23:10:17.470Z
Learning: In ghost/core/core/server/services/member-welcome-emails/jobs/lib/process-entries.js and the outbox processing flow, entries are marked as PROCESSING before being processed. If a failure occurs after email send but before deletion, the entry remains stuck in PROCESSING state (not reprocessed). This intentional design prevents duplicate emails. Handling stuck PROCESSING entries is planned for a separate PR.
📚 Learning: 2025-11-10T23:10:17.470Z
Learnt from: troyciesco
Repo: TryGhost/Ghost PR: 25288
File: ghost/core/core/server/services/member-welcome-emails/jobs/lib/process-entries.js:46-64
Timestamp: 2025-11-10T23:10:17.470Z
Learning: In ghost/core/core/server/services/member-welcome-emails/jobs/lib/process-entries.js and the outbox processing flow, entries are marked as PROCESSING before being processed. If a failure occurs after email send but before deletion, the entry remains stuck in PROCESSING state (not reprocessed). This intentional design prevents duplicate emails. Handling stuck PROCESSING entries is planned for a separate PR.

Applied to files:

  • ghost/core/test/unit/server/services/members/members-api/repositories/MemberRepository.test.js
  • ghost/core/test/integration/services/member-welcome-emails.test.js
  • ghost/core/core/server/services/members/members-api/repositories/MemberRepository.js
📚 Learning: 2025-03-13T09:00:20.205Z
Learnt from: mike182uk
Repo: TryGhost/Ghost PR: 22471
File: apps/admin-x-activitypub/src/utils/pending-activity.ts:13-71
Timestamp: 2025-03-13T09:00:20.205Z
Learning: The pending activity utilities in the Ghost ActivityPub module are covered by tests in the file `apps/admin-x-activitypub/test/unit/utils/pending-activity.ts`.

Applied to files:

  • ghost/core/test/integration/services/member-welcome-emails.test.js
🧬 Code graph analysis (3)
ghost/core/test/unit/server/services/members/members-api/repositories/MemberRepository.test.js (4)
ghost/core/core/server/services/members/members-api/repositories/MemberRepository.js (1)
  • config (11-11)
ghost/core/core/server/services/member-welcome-emails/service.js (1)
  • config (5-5)
ghost/core/core/server/services/members/members-api/members-api.js (1)
  • MemberRepository (10-10)
ghost/core/core/server/models/outbox.js (1)
  • Outbox (10-19)
ghost/core/test/integration/services/member-welcome-emails.test.js (1)
ghost/core/core/server/services/outbox/jobs/lib/process-entries.js (1)
  • payload (51-51)
ghost/core/core/server/services/members/members-api/repositories/MemberRepository.js (2)
ghost/core/core/server/services/members/members-api/members-api.js (1)
  • newMember (282-282)
ghost/core/core/server/services/stripe/services/webhook/CheckoutSessionEventService.js (1)
  • memberData (197-197)
🔇 Additional comments (1)
ghost/core/test/integration/services/member-welcome-emails.test.js (1)

71-82: Status assertion matches new free‑signup contract

Asserting payload.status === 'free' keeps the integration test aligned with the new outbox payload shape and will catch regressions if the free/paid gating changes in future.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

deploy-to-staging Optionally deploy PR to staging

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants