Skip to content

Switched from automated emails table to welcome email automation tables#27185

Merged
EvanHahn merged 10 commits intomainfrom
NY-1188-part-3
Apr 8, 2026
Merged

Switched from automated emails table to welcome email automation tables#27185
EvanHahn merged 10 commits intomainfrom
NY-1188-part-3

Conversation

@EvanHahn
Copy link
Copy Markdown
Contributor

@EvanHahn EvanHahn commented Apr 6, 2026

towards https://linear.app/ghost/issue/NY-1188
ref #27183
ref #27184

Previous patches added new dormant tables and models. This change actually uses them.

More specifically, this does a database migration to move automated_emails to welcome_email_automations and welcome_email_automated_emails. Then, it updates all relevant code to use those new tables.

The old model is deleted, but the tables are not. (That's forthcoming.)

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 6, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a7281a9c-f268-4a13-92ef-29cac5240240

📥 Commits

Reviewing files that changed from the base of the PR and between 9eecec4 and db9a8a1.

📒 Files selected for processing (4)
  • ghost/core/core/server/api/endpoints/automated-emails.js
  • ghost/core/core/server/services/member-welcome-emails/service.js
  • ghost/core/test/e2e-api/admin/automated-emails.test.js
  • ghost/core/test/integration/services/member-welcome-emails.test.js

Walkthrough

Replaces the single AutomatedEmail model/table with two tables/models: welcome_email_automations (automation metadata) and welcome_email_automated_emails (email content). Adds transactional migrations to split existing automated_emails rows and to retarget automated_email_recipients.automated_email_id to the new email table. Updates controllers, services, repositories, outbox handlers, and tests to use WelcomeEmailAutomation with a related welcomeEmailAutomatedEmail, introduces a flattenAutomation helper to return the prior response shape, and makes create/edit operations transactional across both tables. Adds/adjusts model relations and lifecycle hooks and updates the schema hash for tests.

Possibly related PRs

Suggested reviewers

  • cmraible
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ 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%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: switching from the automated_emails table to welcome_email_automations and welcome_email_automated_emails tables.
Description check ✅ Passed The description relates to the changeset by explaining the migration from automated_emails to welcome_email_automations/automated_emails tables, which aligns with the actual code changes present.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch NY-1188-part-3

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
Copy Markdown
Contributor

github-actions bot commented Apr 6, 2026

It looks like this PR contains a migration 👀
Here's the checklist for reviewing migrations:

General requirements

  • ⚠️ Tested performance on staging database servers, as performance on local machines is not comparable to a production environment
  • Satisfies idempotency requirement (both up() and down())
  • Does not reference models
  • Filename is in the correct format (and correctly ordered)
  • Targets the next minor version
  • All code paths have appropriate log messages
  • Uses the correct utils
  • Contains a minimal changeset
  • Does not mix DDL/DML operations
  • Tested in MySQL and SQLite

Schema changes

  • Both schema change and related migration have been implemented
  • For index changes: has been performance tested for large tables
  • For new tables/columns: fields use the appropriate predefined field lengths
  • For new tables/columns: field names follow the appropriate conventions
  • Does not drop a non-alpha table outside of a major version

Data changes

  • Mass updates/inserts are batched appropriately
  • Does not loop over large tables/datasets
  • Defends against missing or invalid data
  • For settings updates: follows the appropriate guidelines

@github-actions github-actions bot added the migration [pull request] Includes migration for review label Apr 6, 2026
@github-actions

This comment was marked as outdated.

@github-actions

This comment was marked as outdated.

@EvanHahn EvanHahn marked this pull request as ready for review April 6, 2026 19:45
@EvanHahn EvanHahn requested a review from cmraible April 6, 2026 19:47
Copy link
Copy Markdown
Collaborator

@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.

Nice one! I've tested this out with welcome emails and it's all working flawlessly 👌

One suggestion for the migration, but otherwise all looks good to me.

EvanHahn added a commit that referenced this pull request Apr 7, 2026
@EvanHahn EvanHahn requested a review from cmraible April 7, 2026 15:18
Base automatically changed from NY-1188-part-2 to main April 7, 2026 17:59
EvanHahn added 2 commits April 7, 2026 13:03
towards https://linear.app/ghost/issue/NY-1188
ref #27183
ref #27184

Previous patches added new dormant tables and models. This change
actually uses them.

More specifically, this does a database migration to move
`automated_emails` to `welcome_email_automations` and
`welcome_email_automated_emails`. Then, it updates all relevant code to
use those new tables.

The old model is deleted, but the tables are not. (That's forthcoming.)
Copy link
Copy Markdown
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: 2

🧹 Nitpick comments (6)
ghost/core/core/server/api/endpoints/automated-emails.js (1)

104-116: Minor: Redundant welcome_email_automation_id assignment.

Line 106 assigns emailData.welcome_email_automation_id = automation.id, and line 110 sets it again in the object literal. The second assignment is sufficient; line 106 can be removed.

♻️ Suggested cleanup
             return models.Base.transaction(async (transacting) => {
                 const automation = await models.WelcomeEmailAutomation.add(automationData, {...frame.options, transacting});
-                emailData.welcome_email_automation_id = automation.id;
                 const email = await models.WelcomeEmailAutomatedEmail.add(
                     {
                         ...emailData,
                         welcome_email_automation_id: automation.id,
                         delay_days: 0
                     },
                     {...frame.options, transacting}
                 );
                 return flattenAutomation(automation, email);
             });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ghost/core/core/server/api/endpoints/automated-emails.js` around lines 104 -
116, Remove the redundant assignment to emailData.welcome_email_automation_id
inside the transaction: after creating the automation with
models.WelcomeEmailAutomation.add, don’t mutate emailData (the line setting
emailData.welcome_email_automation_id = automation.id); rely on the explicit
property passed into the object literal for
models.WelcomeEmailAutomatedEmail.add (which already sets
welcome_email_automation_id: automation.id), leaving
flattenAutomation(automation, email) unchanged.
ghost/core/core/server/models/welcome-email-automation.js (1)

45-51: Consider clarifying the logged field name.

The log entry uses automated_email_id: model.id, but model.id is actually the WelcomeEmailAutomation ID, not the email ID. This naming might be intentional for backward compatibility with existing log parsing, but could be confusing.

If this naming is intentional for compatibility, consider adding a brief comment. Otherwise, automation_id would more accurately describe the value.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ghost/core/core/server/models/welcome-email-automation.js` around lines 45 -
51, The log field automated_email_id is misleading because it contains the
WelcomeEmailAutomation ID (model.id) rather than an email ID; update the
logging.info call (the object passed to logging.info in the isEnableTransition
block) to either rename the field to automation_id and update any downstream log
parsers/consumers to use automation_id, or, if keeping automated_email_id for
backward compatibility, add a concise inline comment next to the logging.info
call explaining that model.id is the WelcomeEmailAutomation ID and the name is
preserved for compatibility (refer to logging.info, automated_email_id,
model.id, isEnableTransition and slug to locate the code).
ghost/core/test/unit/server/services/outbox/handlers/member-created.test.js (1)

22-30: Add coverage for the “automation exists but has no related email” branch.

The handler now has a separate warning/early-return path when welcomeEmailAutomatedEmail is missing, but this suite still only exercises findOne() returning null.

🧪 Suggested test case
+    it('logs warning when automation has no related email content', async function () {
+        WelcomeEmailAutomationStub.findOne.resolves({
+            id: 'automation123',
+            related: sinon.stub().withArgs('welcomeEmailAutomatedEmail').returns({})
+        });
+
+        await handler.handle({
+            payload: {
+                memberId: 'member123',
+                uuid: 'uuid-123',
+                email: 'test@example.com',
+                name: 'Test Member',
+                status: 'free'
+            }
+        });
+
+        const warningLog = findByEvent(logCapture.output, 'outbox.member_created.no_automated_email');
+        assert.ok(warningLog);
+        sinon.assert.notCalled(AutomatedEmailRecipientStub.add);
+    });

Also applies to: 104-105

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ghost/core/test/unit/server/services/outbox/handlers/member-created.test.js`
around lines 22 - 30, Add a test in the member-created suite that simulates
WelcomeEmailAutomationStub.findOne resolving to an automation object whose
related('welcomeEmailAutomatedEmail') returns undefined (i.e., no related email)
to exercise the early-return/warning branch; in the new test stub the automation
should have an id but its related method should return undefined for
'welcomeEmailAutomatedEmail', then call the handler (the member-created handler
under test) and assert it logs the expected warning and does not proceed with
sending an automated email. Also add the analogous case referenced around the
other assertions (lines ~104-105) to ensure both branches are covered.
ghost/core/test/integration/jobs/process-outbox.test.js (1)

31-31: Please turn this into an end-to-end assertion of the tracking write.

member-created.js catches AutomatedEmailRecipient.add() errors, so this setup can still go green even if the new welcome_email_automated_emails lookup or automated_email_id insert is broken. Keep the seeded email id around, assert the matching automated_email_recipients row, and delete those recipient rows before deleting the automation.

Also applies to: 67-83

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ghost/core/test/integration/jobs/process-outbox.test.js` at line 31, Keep the
seeded automated email id and replace the mere deletion of
welcome_email_automations with an end-to-end assertion that the tracking write
created the corresponding automated_email_recipients row: after triggering the
job (member-created.js which calls AutomatedEmailRecipient.add()), query the
welcome_email_automated_emails table to retrieve the seeded automated_email_id,
assert that a row exists in automated_email_recipients with that
automated_email_id and the expected member info, then delete the
automated_email_recipients rows before finally deleting the
welcome_email_automations/welcome_email_automated_emails seed rows; apply the
same change for the other setup/teardown block referenced (lines ~67-83).
ghost/core/core/server/services/outbox/handlers/member-created.js (1)

49-55: Use a distinct warning event for the new misconfiguration path.

Lines 52-55 reuse outbox.member_created.no_automated_email, so log-based alerts cannot distinguish “no automation for this slug” from “automation exists but has no related email row”. A separate system.event would make the new warning actionable.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ghost/core/core/server/services/outbox/handlers/member-created.js` around
lines 49 - 55, The existing logging.warn call in the member-created outbox
handler reuses system.event 'outbox.member_created.no_automated_email' causing
ambiguity; change that event name to a distinct identifier (e.g.
'outbox.member_created.automated_email_missing_row' or similar) so alerts can
distinguish the new misconfiguration path where an automation exists but has no
related email row; update the logging.warn invocation that uses LOG_KEY and slug
(located in member-created.js near the block that checks if (!email ||
!email.id)) to emit the new event string while preserving the same message and
metadata shape.
ghost/core/core/server/services/members/members-api/repositories/member-repository.js (1)

67-68: Consider centralizing the welcome-email activation lookup.

The WelcomeEmailAutomation rewrite looks right, but the same findOne(...withRelated...) + lexical + status predicate now exists for free signups, paid upgrades, and member-welcome-emails/service.js. Pulling that into one helper would reduce the odds of enqueue-time and send-time behavior drifting on the next schema tweak.

Also applies to: 87-106, 362-373, 1480-1491

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@ghost/core/core/server/services/members/members-api/repositories/member-repository.js`
around lines 67 - 68, Multiple places duplicate the WelcomeEmailAutomation
lookup (findOne(...withRelated...) plus checking lexical and status) across
MemberRepository and member-welcome-emails/service.js; extract that logic into a
single exported helper (e.g., a function like getActiveWelcomeEmailAutomation or
WelcomeEmailAutomation.findActive) and replace the inline queries in
member-repository methods (the blocks around WelcomeEmailAutomation usage at
~67-68, 87-106, 362-373, 1480-1491) and in member-welcome-emails/service.js to
call this helper so all callers share the same withRelated, lexical and status
predicates and reduce drift on future schema changes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@ghost/core/core/server/data/migrations/versions/6.27/2026-04-06-15-55-20-split-automated-emails-into-welcome-email-tables.js`:
- Around line 60-65: Add a clear comment inside the async function down()
explaining that this rollback depends on the foreign key being removed by the
separate migration
2026-04-07-15-10-32-update-automated-email-recipients-foreign-key.js (which
drops the FK before this down() runs) and that the FK is restored to point back
to automated_emails; explicitly state that manually running this down() out of
order may fail or require first removing/restoring the FK on
automated_email_recipients to avoid constraint violations so maintainers know
the dependency when reversing migrations.

In `@ghost/core/core/server/services/member-welcome-emails/service.js`:
- Around line 195-197: The existence check for the related welcome email is
using object truthiness on automation.related('welcomeEmailAutomatedEmail'),
which is unreliable; change the logic to first ensure WelcomeEmailAutomation
(automation) exists, then fetch the related model into a variable (e.g., const
email = automation.related('welcomeEmailAutomatedEmail')) and validate by
checking email and email.id (e.g., if (!automation || !email || !email.id) ...)
so automations with no child row are correctly rejected; update any branches
that rely on the prior check to use this new email/id check.

---

Nitpick comments:
In `@ghost/core/core/server/api/endpoints/automated-emails.js`:
- Around line 104-116: Remove the redundant assignment to
emailData.welcome_email_automation_id inside the transaction: after creating the
automation with models.WelcomeEmailAutomation.add, don’t mutate emailData (the
line setting emailData.welcome_email_automation_id = automation.id); rely on the
explicit property passed into the object literal for
models.WelcomeEmailAutomatedEmail.add (which already sets
welcome_email_automation_id: automation.id), leaving
flattenAutomation(automation, email) unchanged.

In `@ghost/core/core/server/models/welcome-email-automation.js`:
- Around line 45-51: The log field automated_email_id is misleading because it
contains the WelcomeEmailAutomation ID (model.id) rather than an email ID;
update the logging.info call (the object passed to logging.info in the
isEnableTransition block) to either rename the field to automation_id and update
any downstream log parsers/consumers to use automation_id, or, if keeping
automated_email_id for backward compatibility, add a concise inline comment next
to the logging.info call explaining that model.id is the WelcomeEmailAutomation
ID and the name is preserved for compatibility (refer to logging.info,
automated_email_id, model.id, isEnableTransition and slug to locate the code).

In
`@ghost/core/core/server/services/members/members-api/repositories/member-repository.js`:
- Around line 67-68: Multiple places duplicate the WelcomeEmailAutomation lookup
(findOne(...withRelated...) plus checking lexical and status) across
MemberRepository and member-welcome-emails/service.js; extract that logic into a
single exported helper (e.g., a function like getActiveWelcomeEmailAutomation or
WelcomeEmailAutomation.findActive) and replace the inline queries in
member-repository methods (the blocks around WelcomeEmailAutomation usage at
~67-68, 87-106, 362-373, 1480-1491) and in member-welcome-emails/service.js to
call this helper so all callers share the same withRelated, lexical and status
predicates and reduce drift on future schema changes.

In `@ghost/core/core/server/services/outbox/handlers/member-created.js`:
- Around line 49-55: The existing logging.warn call in the member-created outbox
handler reuses system.event 'outbox.member_created.no_automated_email' causing
ambiguity; change that event name to a distinct identifier (e.g.
'outbox.member_created.automated_email_missing_row' or similar) so alerts can
distinguish the new misconfiguration path where an automation exists but has no
related email row; update the logging.warn invocation that uses LOG_KEY and slug
(located in member-created.js near the block that checks if (!email ||
!email.id)) to emit the new event string while preserving the same message and
metadata shape.

In `@ghost/core/test/integration/jobs/process-outbox.test.js`:
- Line 31: Keep the seeded automated email id and replace the mere deletion of
welcome_email_automations with an end-to-end assertion that the tracking write
created the corresponding automated_email_recipients row: after triggering the
job (member-created.js which calls AutomatedEmailRecipient.add()), query the
welcome_email_automated_emails table to retrieve the seeded automated_email_id,
assert that a row exists in automated_email_recipients with that
automated_email_id and the expected member info, then delete the
automated_email_recipients rows before finally deleting the
welcome_email_automations/welcome_email_automated_emails seed rows; apply the
same change for the other setup/teardown block referenced (lines ~67-83).

In `@ghost/core/test/unit/server/services/outbox/handlers/member-created.test.js`:
- Around line 22-30: Add a test in the member-created suite that simulates
WelcomeEmailAutomationStub.findOne resolving to an automation object whose
related('welcomeEmailAutomatedEmail') returns undefined (i.e., no related email)
to exercise the early-return/warning branch; in the new test stub the automation
should have an id but its related method should return undefined for
'welcomeEmailAutomatedEmail', then call the handler (the member-created handler
under test) and assert it logs the expected warning and does not proceed with
sending an automated email. Also add the analogous case referenced around the
other assertions (lines ~104-105) to ensure both branches are covered.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 758332e3-18c4-4623-a654-e799407251c0

📥 Commits

Reviewing files that changed from the base of the PR and between 3e197d9 and 46ccd2a.

📒 Files selected for processing (24)
  • ghost/core/core/server/api/endpoints/automated-emails.js
  • ghost/core/core/server/data/migrations/versions/6.27/2026-04-06-15-55-20-split-automated-emails-into-welcome-email-tables.js
  • ghost/core/core/server/data/migrations/versions/6.27/2026-04-07-15-10-32-update-automated-email-recipients-foreign-key.js
  • ghost/core/core/server/data/schema/schema.js
  • ghost/core/core/server/models/automated-email-recipient.js
  • ghost/core/core/server/models/automated-email.js
  • ghost/core/core/server/models/welcome-email-automated-email.js
  • ghost/core/core/server/models/welcome-email-automation.js
  • ghost/core/core/server/services/member-welcome-emails/service.js
  • ghost/core/core/server/services/members/api.js
  • ghost/core/core/server/services/members/members-api/members-api.js
  • ghost/core/core/server/services/members/members-api/repositories/event-repository.js
  • ghost/core/core/server/services/members/members-api/repositories/member-repository.js
  • ghost/core/core/server/services/outbox/handlers/member-created.js
  • ghost/core/test/e2e-api/admin/automated-emails.test.js
  • ghost/core/test/integration/jobs/process-outbox.test.js
  • ghost/core/test/integration/services/member-welcome-emails.test.js
  • ghost/core/test/unit/server/data/schema/integrity.test.js
  • ghost/core/test/unit/server/models/automated-email.test.js
  • ghost/core/test/unit/server/models/welcome-email-automated-email.test.js
  • ghost/core/test/unit/server/models/welcome-email-automation.test.js
  • ghost/core/test/unit/server/services/members/members-api/repositories/event-repository.test.js
  • ghost/core/test/unit/server/services/members/members-api/repositories/member-repository.test.js
  • ghost/core/test/unit/server/services/outbox/handlers/member-created.test.js
💤 Files with no reviewable changes (2)
  • ghost/core/test/unit/server/models/automated-email.test.js
  • ghost/core/core/server/models/automated-email.js

Copy link
Copy Markdown
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.

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

107-112: Consider checking the relation's ID for consistency.

The !email check at line 109 is always false for Bookshelf models since .related() returns a model object even when the related row is absent. The code works correctly because !email.get('lexical') catches empty models, but checking the ID would be more explicit and consistent with the pattern used at line 197.

♻️ Optional: More explicit empty-relation check
         const email = row.related('welcomeEmailAutomatedEmail');

-        if (!email || !email.get('lexical')) {
+        if (!email?.id || !email.get('lexical')) {
             this.#memberWelcomeEmails[memberStatus] = null;
             continue;
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ghost/core/core/server/services/member-welcome-emails/service.js` around
lines 107 - 112, The current check uses `!email` which is ineffective for
Bookshelf relations because `.related()` returns a model object even when
missing; update the condition to explicitly check the related model's id (e.g.
`!email.id` or `!email.get('id')`) along with the lexical check so the block
that sets `this.#memberWelcomeEmails[memberStatus] = null` and continues runs
when the relation is absent or has no lexical content; locate the code around
the `const email = row.related('welcomeEmailAutomatedEmail')` line in the
member-welcome-emails service and replace the `if (!email ||
!email.get('lexical'))` check accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@ghost/core/core/server/services/member-welcome-emails/service.js`:
- Around line 107-112: The current check uses `!email` which is ineffective for
Bookshelf relations because `.related()` returns a model object even when
missing; update the condition to explicitly check the related model's id (e.g.
`!email.id` or `!email.get('id')`) along with the lexical check so the block
that sets `this.#memberWelcomeEmails[memberStatus] = null` and continues runs
when the relation is absent or has no lexical content; locate the code around
the `const email = row.related('welcomeEmailAutomatedEmail')` line in the
member-welcome-emails service and replace the `if (!email ||
!email.get('lexical'))` check accordingly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a54b62b9-7e25-4f9a-9d3b-38028eb00495

📥 Commits

Reviewing files that changed from the base of the PR and between 46ccd2a and d9dc761.

📒 Files selected for processing (1)
  • ghost/core/core/server/services/member-welcome-emails/service.js

Copy link
Copy Markdown
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.

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

213-215: Use the already-defined automatedEmail variable in the existence check.

The automatedEmail variable is defined on line 213 but the check on line 215 calls .related() again. This is redundant since the variable is already used later (line 239).

♻️ Suggested simplification
         const automatedEmail = automation?.related('welcomeEmailAutomatedEmail');
 
-        if (!automation || !automation.related('welcomeEmailAutomatedEmail')?.id) {
+        if (!automation || !automatedEmail?.id) {
             throw new errors.NotFoundError({
                 message: MESSAGES.NO_MEMBER_WELCOME_EMAIL
             });
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ghost/core/core/server/services/member-welcome-emails/service.js` around
lines 213 - 215, The check redundantly calls
automation.related('welcomeEmailAutomatedEmail') again instead of using the
already-defined automatedEmail variable; update the condition to use
automatedEmail (e.g., if (!automation || !automatedEmail?.id)) so the code
references the precomputed automatedEmail and avoids the duplicate related()
call while preserving the same early-return behavior in the
member-welcome-emails service.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@ghost/core/core/server/services/member-welcome-emails/service.js`:
- Around line 213-215: The check redundantly calls
automation.related('welcomeEmailAutomatedEmail') again instead of using the
already-defined automatedEmail variable; update the condition to use
automatedEmail (e.g., if (!automation || !automatedEmail?.id)) so the code
references the precomputed automatedEmail and avoids the duplicate related()
call while preserving the same early-return behavior in the
member-welcome-emails service.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 295e33ca-a55c-4ae8-bb12-b2edc9fb5f11

📥 Commits

Reviewing files that changed from the base of the PR and between d9dc761 and 88e7de6.

📒 Files selected for processing (2)
  • ghost/core/core/server/services/member-welcome-emails/service.js
  • ghost/core/test/integration/services/member-welcome-emails.test.js
🚧 Files skipped from review as they are similar to previous changes (1)
  • ghost/core/test/integration/services/member-welcome-emails.test.js

@EvanHahn EvanHahn marked this pull request as draft April 7, 2026 23:08
@EvanHahn
Copy link
Copy Markdown
Contributor Author

EvanHahn commented Apr 7, 2026

0d5af31 was a little disruptive here, so I had to make a few changes.

@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud bot commented Apr 7, 2026

Quality Gate Failed Quality Gate failed

Failed conditions
13.9% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

@EvanHahn EvanHahn marked this pull request as ready for review April 8, 2026 01:15
@EvanHahn EvanHahn merged commit a597db6 into main Apr 8, 2026
37 of 39 checks passed
@EvanHahn EvanHahn deleted the NY-1188-part-3 branch April 8, 2026 01:15
EvanHahn added a commit that referenced this pull request Apr 8, 2026
closes https://linear.app/ghost/issue/NY-1188
ref #27185

This removes the old automated emails table now that we aren't using it
anymore.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

migration [pull request] Includes migration for review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants